<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Datatables - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Datatables - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 22 May 2026 17:40:23 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/datatables/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Pivot Table in Excel ]]>
                </title>
                <description>
                    <![CDATA[ In Excel, pivot tables let you analyze and visualize your data in an easy way.  With pivot tables, you can make comparisons and create calculations more quickly. You can even create charts to visualize your data. Creating pivot tables might be intimi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-a-pivot-table-in-excel/</link>
                <guid isPermaLink="false">66adf1106778e7bd69427bfc</guid>
                
                    <category>
                        <![CDATA[ charts ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Datatables ]]>
                    </category>
                
                    <category>
                        <![CDATA[ excel ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kolade Chris ]]>
                </dc:creator>
                <pubDate>Wed, 14 Sep 2022 22:35:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/pivotTable.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In Excel, pivot tables let you analyze and visualize your data in an easy way. </p>
<p>With pivot tables, you can make comparisons and create calculations more quickly. You can even create charts to visualize your data.</p>
<p>Creating pivot tables might be intimidating if you're doing it for the first time. But in this article, I’m going to explain everything you need to start creating pivot tables.</p>
<p>It doesn’t end there – I will also show you how to add charts so you can visualize your data.</p>
<p>In addition, the version of Excel you’re using doesn’t matter. You can even create a Pivot table in Excel 2013. In fact, I used Excel 13 to get set for this article.</p>
<h2 id="heading-what-well-cover">What We'll Cover</h2>
<ul>
<li><a class="post-section-overview" href="#heading-how-to-create-a-pivot-table-in-excel">How to Create a Pivot Table in Excel</a><ul>
<li><a class="post-section-overview" href="#heading-how-to-create-rows-and-make-calculations-with-a-pivot-table">How to Create Rows and Make Calculations with a Pivot Table</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-entirely-new-rows-with-a-pivot-table">How to Create Entirely New Rows with a Pivot Table</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-implement-graphical-visualization-for-a-pivot-table">How to Implement Graphical Visualization for a Pivot Table</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ul>
<h2 id="heading-how-to-create-a-pivot-table-in-excel">How to Create a Pivot Table in Excel</h2>
<p>To show you how to create a pivot table, I have created a table of some fictional footballers showing:</p>
<ul>
<li>their names</li>
<li>the number of matches they've played</li>
<li>their assists and goals</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss1-3.png" alt="ss1-3" width="600" height="400" loading="lazy"> </p>
<p>I will be creating extra rows of <code>Goal Contributions</code> and <code>Goal Ratio</code>, also called Goals per Game.</p>
<p>In football (Soccer), goal contributions is the total number of goals and assists. The goal ratio is derived when the number of goals is divided by the number of matches played.</p>
<p><strong>To create a pivot table, follow the steps below</strong>:</p>
<p><strong>Step 1</strong>: In the menu bar, click “Insert” and select “Pivot Table”:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss2-3.png" alt="ss2-3" width="600" height="400" loading="lazy"> </p>
<p><strong>Step 2</strong>: Leave everything as it is and select “OK”:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss3-3.png" alt="ss3-3" width="600" height="400" loading="lazy"> </p>
<p>You should use a new worksheet so you can have a dedicated sheet for your pivot table.</p>
<p>The next interface you’ll see looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss4-3.png" alt="ss4-3" width="600" height="400" loading="lazy"></p>
<p>You’ll be working with the part where you see “PivotTable Fields”. You will even see the columns of your table there.</p>
<h3 id="heading-how-to-create-rows-and-make-calculations-with-a-pivot-table">How to Create Rows and Make Calculations with a Pivot Table</h3>
<p>This is the part where you can create rows, columns, and make calculations.</p>
<p>To create rows for your pivot table, drag one of the rows in the existing table to the part where you see “ROWS”. </p>
<p>For instance, I want to create a row for the pivot table with the name row of the original table. That means I have to drag the name row to the ROWS area:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss5-3.png" alt="ss5-3" width="600" height="400" loading="lazy"></p>
<p>You can see I’ve created a row with the name row of the original table.</p>
<p>To make calculations easily, you can use the “VALUES” area.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss6-1.png" alt="ss6-1" width="600" height="400" loading="lazy"> </p>
<p>I want to see the number of goals scored by each player. So, I’ll drag the “Goal scored” row to the “VALUES” area:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss7-1.png" alt="ss7-1" width="600" height="400" loading="lazy"></p>
<p>You can see I can directly visualize the number of goals scored by each footballer.</p>
<p>You can also make other calculations in the Values area. Just click the dropdown in front of the column right there and select “Value Field Settings…”:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss8-1.png" alt="ss8-1" width="600" height="400" loading="lazy"></p>
<p>I want to see the highest goal scored instead of the total goals scored by all the players. So I’ll select “MAX” and click “OK”:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss9-1.png" alt="ss9-1" width="600" height="400" loading="lazy"></p>
<p>Now I can see the maximum goals scored instead of the total of all goals scored:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss10-1.png" alt="ss10-1" width="600" height="400" loading="lazy"> </p>
<h3 id="heading-how-to-create-entirely-new-rows-with-a-pivot-table">How to Create Entirely New Rows with a Pivot Table</h3>
<p>Remember I said I would create extra rows of Goal Contributions and Goal Ratio, also called Goals per Game? So, let’s do it.</p>
<p>I need the Assists Created and Goal Scored rows to calculate goal contributions. So, I’ll make sure both of them are in the Values area:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss11-1.png" alt="ss11-1" width="600" height="400" loading="lazy"> </p>
<p>Now, I’ll make sure the “Analyze” tab is selected, click “Fields, Items, &amp; Sets”, then select “Calculated Field…”:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss12-1.png" alt="ss12-1" width="600" height="400" loading="lazy"> </p>
<p>The next interface you’ll see looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss13-1.png" alt="ss13-1" width="600" height="400" loading="lazy"> </p>
<p>Here, I’ll do three things:</p>
<ul>
<li>type the name of the row in the name field</li>
<li>write the formula – in this case, “Assists Created + Goal Scored”</li>
<li>click Add and OK</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/new-pivot-table-row.gif" alt="new-pivot-table-row" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss14-1.png" alt="ss14-1" width="600" height="400" loading="lazy"></p>
<p>Now, I have successfully created the Goal Contributions row:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss15-1.png" alt="ss15-1" width="600" height="400" loading="lazy"></p>
<p>To create the Goal Ratio, I have to make sure the matches played row is in the VALUES area:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss16-1.png" alt="ss16-1" width="600" height="400" loading="lazy"> </p>
<p>The formula I’ll use is Goal Scored / Matches played. So, I’ll implement calculated fields again:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss17-1.png" alt="ss17-1" width="600" height="400" loading="lazy"> </p>
<p>I can now see the goal ratio of each footballer:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss18-1.png" alt="ss18-1" width="600" height="400" loading="lazy"> </p>
<h2 id="heading-how-to-implement-graphical-visualization-for-a-pivot-table">How to Implement Graphical Visualization for a Pivot Table</h2>
<p>It’s nice to create a pivot table and implement calculations easily, but it’s nicer to see the graphical representation of that pivot table in a chart.</p>
<p>To represent the pivot table in a chart:</p>
<p><strong>Step 1</strong>: Make sure the “Analyze” tab is selected, then select PivotChart:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss19-1.png" alt="ss19-1" width="600" height="400" loading="lazy"> </p>
<p><strong>Step 2</strong>: Select the type of chart you want on the right. It could be a column, pie chart, or bar chart. Also, select the format in the upper part. It could be 2D or 3D.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss20-1.png" alt="ss20-1" width="600" height="400" loading="lazy"> </p>
<p>Click OK when you are satisfied.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss21.png" alt="ss21" width="600" height="400" loading="lazy"></p>
<p>That’s the chart representing the data.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Pivot tables are one of the most powerful features of Excel. If you have large datasets you have to work with, a pivot table can save you a lot of time when it comes to analysis and visualization.</p>
<p>Pivot tables are nice, but being able to create different types of charts to represent the data is really helpful, too.</p>
<p>I hope this article helps you create a pivot table and charts for the data you’re working with.</p>
<p>If you find this article helpful, don’t hesitate to pass it along to others.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Convert a Static HTML Table to a Dynamic JavaScript Data Grid ]]>
                </title>
                <description>
                    <![CDATA[ By Alan Richardson HTML Tables are simple to use for rendering small amounts of data. But they can be hard for users to work with when they display a lot of data.  Features like sorting, filtering, and pagination make it easier to work with many rows... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/convert-html-table-to-dynamic-javascript-data-grid/</link>
                <guid isPermaLink="false">66d45d5955db48792eed3ef7</guid>
                
                    <category>
                        <![CDATA[ Datatables ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 18 Jan 2022 22:40:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/01/freecodecamp-html-table-migrate.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Alan Richardson</p>
<p>HTML Tables are simple to use for rendering small amounts of data. But they can be hard for users to work with when they display a lot of data. </p>
<p>Features like sorting, filtering, and pagination make it easier to work with many rows of data. We can easily implement those features by migrating from an HTML Table to a JavaScript Data Grid component.</p>
<p>In this post we will use the free community edition of <a target="_blank" href="https://www.ag-grid.com/">AG Grid JavaScript Data Grid</a> to convert from a long static HTML table to an easy to use interactive Data Grid. The amount of JavaScript we need to do this is minimal and very simple.</p>
<p>We will build the example code in three steps:</p>
<ul>
<li>Render a static list of Todo Items data in an HTML Table.</li>
<li>Load a list of Todo Items from a REST API and render in the table.</li>
<li>Convert the HTML Table to a Data Grid to allow sorting, filtering and pagination.</li>
</ul>
<h2 id="heading-how-to-render-data-with-html-tables">How to Render Data with HTML Tables</h2>
<p>The first version of our application will allow us to create the basic page structure and make sure we are rendering the right data for the user.</p>
<p>I create a simple <code>index.html</code> file as shown below:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Table Example<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-tag">table</span> {
            <span class="hljs-attribute">border-collapse</span>: collapse;
            <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
        }

        <span class="hljs-selector-tag">td</span>,
        <span class="hljs-selector-tag">th</span> {
            <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#000000</span>;
            <span class="hljs-attribute">text-align</span>: left;
            <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span>;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>TODO List<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"data-table"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"html-data-table"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>userId<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>id<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>title<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>completed<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>My todo 1<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>false<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>    
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This will render a single Todo Item in a table.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/single-todo-item-html-table.png" alt="Single Todo Item Shown in an HTML Table" width="600" height="400" loading="lazy">
<em>Single Todo Item Shown in an HTML Table</em></p>
<p>Here is the example <a target="_blank" href="https://eviltester.github.io/freecodecampexamples/html-table-to-data-grid/static-html-table.html">Static HTML Table Page</a>.</p>
<p>The <code>table</code> is styled to have a width of 100% of the page using <code>width:100%</code> and the border lines between cells in the table have been styled to show as one line with <code>border-collapse: collapse</code>.</p>
<p>Without the <code>border-collapse</code> value the table would look like the image below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/single-todo-item-html-table-no-border-collapse.png" alt="Table Styled without border-collapse" width="600" height="400" loading="lazy">
<em>Table Styled without border-collapse</em></p>
<h2 id="heading-benefits-of-short-html-tables">Benefits of Short HTML Tables</h2>
<p>HTML Tables are a very fast way to render small amounts of data in a tabular form on a page.</p>
<p>Tables require styling because the default styling of a <code>table</code> varies between browsers and is often shown with no borders making the data hard to read.</p>
<p>At the moment, our list of Todo Items is statically coded into the page. For the next step we will <code>fetch</code> the list from a REST API using JavaScript.</p>
<h2 id="heading-how-to-read-json-from-an-api-to-render-in-an-html-table">How to Read JSON from an API to Render in an HTML Table</h2>
<p>Since we will be loading the data from an API, I won't hard code any data in the table. To support dynamic loading, I simply remove the line of data from the <code>table</code> because I'm going to create the data rows using JavaScript:</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"data-table"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"html-data-table"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>userId<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>id<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>title<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>completed<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>    
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>I will add the JavaScript in the <code>index.html</code> page immediately before the terminating <code>body</code> tag.</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p>To start, I will write the code that reads the data.</p>
<p>I will use the "{JSON} Placeholder" REST API application for this demonstration. By making a <code>GET</code> request on the URL <a target="_blank" href="https://jsonplaceholder.typicode.com/todos">https://jsonplaceholder.typicode.com/todos</a> we will receive a JSON response which is a list of Todo Items.</p>
<p>You can try it for yourself without JavaScript by clicking on the link above.</p>
<p>The easiest way to make a <code>GET</code> request on the API is by using the <code>fetch</code> function built into JavaScript.</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>&gt;</span><span class="javascript">

        fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/todos'</span>)
            .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
                <span class="hljs-keyword">return</span> response.json();
            }).then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">apiJsonData</span>) </span>{
                <span class="hljs-built_in">console</span>.log(apiJsonData);
            })

    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p>To explain the above code, I'll describe it in sections below:</p>
<ul>
<li>Issue a GET request to <code>https://jsonplaceholder.typicode.com/todos</code></li>
</ul>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/todos'</span>)
</code></pre>
<ul>
<li>Then when the request is finished, convert the response to a JavaScript Object – in our case this will be an array containing all the Todo Items.</li>
</ul>
<pre><code class="lang-javascript">.then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
    <span class="hljs-keyword">return</span> response.json();
})
</code></pre>
<ul>
<li>Then write the JavaScript object to the console</li>
</ul>
<pre><code class="lang-javascript">.then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">apiJsonData</span>) </span>{
    <span class="hljs-built_in">console</span>.log(apiJsonData);
})
</code></pre>
<p>With this code in our application, we won't see anything in the table, but we would see the array rendered in the Browser Dev Tools Console where we could view the data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/console-log.png" alt="Data shown when console.log used" width="600" height="400" loading="lazy">
<em>Data shown when console.log used</em></p>
<p>The API call returns 200 items, and each item is a Todo Object:</p>
<pre><code class="lang-json">  {
    <span class="hljs-attr">"userId"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"delectus aut autem"</span>,
    <span class="hljs-attr">"completed"</span>: <span class="hljs-literal">false</span>
  }
</code></pre>
<p>Our next step is to render the data in the table:</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>&gt;</span><span class="javascript">

        fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/todos'</span>)
            .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
                <span class="hljs-keyword">return</span> response.json();
            }).then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">apiJsonData</span>) </span>{
                <span class="hljs-built_in">console</span>.log(apiJsonData);
                renderDataInTheTable(apiJsonData);
            })

        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">renderDataInTheTable</span>(<span class="hljs-params">todos</span>) </span>{
            <span class="hljs-keyword">const</span> mytable = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"html-data-table"</span>);
            todos.forEach(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> {
                <span class="hljs-keyword">let</span> newRow = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"tr"</span>);
                <span class="hljs-built_in">Object</span>.values(todo).forEach(<span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> {
                    <span class="hljs-keyword">let</span> cell = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"td"</span>);
                    cell.innerText = value;
                    newRow.appendChild(cell);
                })
                mytable.appendChild(newRow);
            });
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p>The <code>renderDataInTheTable</code> function finds the table in the DOM so that we can append new rows to it, then loops over all the Todo Items returned from the API call.</p>
<p>For each Todo Item the code creates a new <code>tr</code> element, then adds each value in the Todo Item to the table as a <code>td</code> element.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> newRow = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"tr"</span>);
<span class="hljs-built_in">Object</span>.values(todo).forEach(<span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> cell = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"td"</span>);
    cell.innerText = value;
    newRow.appendChild(cell);
})
</code></pre>
<p>When the <code>fetch</code> and <code>renderDataInTheTable</code> code is added to our application, and the page loads, we will see that the HTML table now has all 200 Todo Items rendered in the table.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/todo-list-200-rows-ez.gif" alt="Dynamically loaded todo list" width="600" height="400" loading="lazy">
<em>Dynamically loaded todo list</em></p>
<p>Here is the example <a target="_blank" href="https://eviltester.github.io/freecodecampexamples/html-table-to-data-grid/table-index.html">Dynamic HTML Table Page</a>.</p>
<h2 id="heading-benefits-and-disadvantages-of-long-html-tables">Benefits and Disadvantages of Long HTML Tables</h2>
<p>HTML Tables are an easy way to render data on a page but are not very usable for long lists of data.</p>
<p>The data items can be hard to find, although the user can search the data by using the built in 'find in the page' functionality of the browser.</p>
<p>By rendering in an HTML table, our users have no way to sort the data, or filter it to show only completed Todo Items. We would have to add extra code to our application to implement sorting and filtering functionality.</p>
<p>HTML Tables will automatically grow as more rows are added to the table. This can make them harder to use in an application when a lot of data has been added.</p>
<p>When we add a lot of data we probably want to have pagination to restrict the table of data to show only a certain number of rows and allow the user to click through to the next page to see more items. This, again, is functionality we would have to write extra code to handle.</p>
<p>When our application gets to the point that we need more user interaction, we should consider using a Data Grid component.</p>
<p>We can use it to add extra functionality like:</p>
<ul>
<li>sorting</li>
<li>filtering</li>
<li>column resizing</li>
<li>pagination</li>
</ul>
<h2 id="heading-data-grid-components-and-libraries">Data Grid Components and Libraries</h2>
<p>There are many free Data Grid Components available, but most of them are framework specific so they require coding using either React, Angular, or Vue.</p>
<p>I'm using <a target="_blank" href="https://www.ag-grid.com/">AG Grid</a> for this example because the free version can be used with JavaScript, TypeScript, React, Angular or Vue. The "AG" stands for Agnostic, meaning can be used with any framework. </p>
<p>When you learn to use AG Grid in one framework, the same API is available for other frameworks, making your knowledge transferrable to other projects.</p>
<p>The free version of AG Grid can be used in commercial applications, so if you manage to expand the demo application shown here into a commercial Todo List Management Application, you'll still be able to use AG Grid for free. Many commercial applications have been built using the free version of AG Grid.</p>
<p>In addition, AG Grid is frequently sought as a skill in job applications, so is worth experimenting with.</p>
<p>The commercial version of AG Grid has extra features like Excel Exporting and creating Charts, but we don't need any of that functionality in this demo.</p>
<p>Using a Data Grid means that we configure the Data Grid, give it the data to render, and the Grid handles all the other functionality like sorting, filtering, and pagination.</p>
<p>We can convert our existing code to use AG Grid with just a few changes.</p>
<h2 id="heading-how-to-add-ag-grid-javascript-and-css">How to Add AG Grid JavaScript and CSS</h2>
<p>AG Grid is a library so we will include the JavaScript required.</p>
<p>If you are using build tools like <code>npm</code>, then various <code>npm install</code> commands are listed in the <a target="_blank" href="https://file+.vscode-resource.vscode-webview.net/Users/alan/Documents/GitHub/alan/freecodecampexamples/docs/html-table-to-data-grid/readme.md">Getting Started with AG Grid</a> documentation.</p>
<p>We are using plain JavaScript, so we can include the <code>script</code> in our <code>head</code> section.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Data Grid Example<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/ag-grid-community/dist/ag-grid-community.min.noStyle.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://unpkg.com/ag-grid-community/dist/styles/ag-grid.css"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://unpkg.com/ag-grid-community/dist/styles/ag-theme-balham.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
</code></pre>
<p>This includes the community edition of AG Grid and the CSS required to render the Grid properly.</p>
<p>Our <code>data-table</code> <code>div</code> no longer needs to have any <code>table</code> element:</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"data-table"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"ag-theme-balham"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>AG Grid will create the HTML for the Data Grid when we set it up. We add the <code>class</code> to use an <a target="_blank" href="https://www.ag-grid.com/javascript-data-grid/themes/">AG Grid theme</a>. In this example we are using the theme <code>ag-theme-balham</code>.</p>
<p>AG Grid requires setting a width and height for the <code>div</code>. I chose to add this as the <code>style</code> section in the code:</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-id">#data-table</span> {
            <span class="hljs-attribute">height</span>: <span class="hljs-number">500px</span>;
            <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>The grid will be shown as 500 pixels high and fill <code>100%</code> width of the screen. This replicates the basic styling we had with the HTML table. But it also shows one of the benefits of using a Data Grid. The size of the table rendered can be easily controlled and scroll bars will be added automatically as necessary by the Grid itself.</p>
<h2 id="heading-how-to-configure-ag-grid-and-render-data">How to Configure AG Grid and Render Data</h2>
<p>The <code>script</code> section of the code changes because we need to:</p>
<ul>
<li>Configure the data grid.</li>
<li>Create a new data grid using the configuration.</li>
<li>Fetch the data and add it to the grid.</li>
</ul>
<p>I'll show the initial amended <code>script</code> section below and then explain it in the following paragraphs.</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>&gt;</span><span class="javascript">

        <span class="hljs-keyword">const</span> columnDefs = [
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'userId'</span> },
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'id'</span> },
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'title'</span> },
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'completed'</span> },
        ];

        <span class="hljs-keyword">const</span> gridOptions = {
            <span class="hljs-attr">columnDefs</span>: columnDefs,
            <span class="hljs-attr">onGridReady</span>: <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span>{renderDataInTheTable(event.api)}
        };

        <span class="hljs-keyword">const</span> eGridDiv = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'data-table'</span>);
        <span class="hljs-keyword">new</span> agGrid.Grid(eGridDiv, gridOptions);

        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">renderDataInTheTable</span>(<span class="hljs-params">api</span>) </span>{
            fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/todos'</span>)
                .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
                    <span class="hljs-keyword">return</span> response.json();
                }).then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{
                    api.setRowData(data);
                    api.sizeColumnsToFit();
                })
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>A Data Grid is data- and configuration-driven – we don't have to write much code in order to create a functional Data Grid.</p>
<p>First we create an array of Column Objects which define the columns in the Data Grid. These columns map on to the data.</p>
<p>The data that we are receiving from the API call has four properties: "userId", "id", "title" and "completed":</p>
<pre><code class="lang-json">  {
    <span class="hljs-attr">"userId"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"delectus aut autem"</span>,
    <span class="hljs-attr">"completed"</span>: <span class="hljs-literal">false</span>
  }
</code></pre>
<p>To render these in the Data Grid as columns, we create an Object with a <code>field</code> property where the value is the name of the property in the Data Object.</p>
<pre><code class="lang-javascript">        <span class="hljs-keyword">const</span> columnDefs = [
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'userId'</span> },
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'id'</span> },
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'title'</span> },
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'completed'</span> },
        ];
</code></pre>
<p>Next we create the <code>gridOptions</code> object. This configures the Data Grid:</p>
<pre><code class="lang-javascript">        <span class="hljs-keyword">const</span> gridOptions = {
            <span class="hljs-attr">columnDefs</span>: columnDefs,
            <span class="hljs-attr">onGridReady</span>: <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span>{renderDataInTheTable(event.api)}
        };
</code></pre>
<p>The <code>columnDefs</code> property is assigned the array of Column Objects that we defined earlier.</p>
<p>The <code>onGridReady</code> property is assigned a function which will call the <code>renderDataInTheTable</code> function when the grid has been created and rendered in the DOM (that is, when the grid is ready).</p>
<p>To add the grid to the page, we find the <code>div</code> element which will contain the grid, then instantiate a new AG Grid object for that element and with the options we configured:</p>
<pre><code class="lang-javascript">        <span class="hljs-keyword">const</span> eGridDiv = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'data-table'</span>);
        <span class="hljs-keyword">new</span> agGrid.Grid(eGridDiv, gridOptions);
</code></pre>
<p>The function to fetch the data and render the data in the grid is much the same <code>fetch</code> code that we used for the dynamic HTML table. The difference is that the <code>renderDataInTheTable</code> function receives an AG Grid Api object as a parameter, allowing us to call AG Grid functionality to set the row data and size the columns to fit the grid:</p>
<pre><code class="lang-javascript">        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">renderDataInTheTable</span>(<span class="hljs-params">api</span>) </span>{
            fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/todos'</span>)
                .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
                    <span class="hljs-keyword">return</span> response.json();
                }).then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{
                    api.setRowData(data);
                    api.sizeColumnsToFit();
                })
        }
</code></pre>
<p>When this code runs, we will have basically replicated the same functionality of the dynamic HTML table, but now all the data is shown in a Data Grid with a scroll bar.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/initial-data-grid.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To receive the benefits of using a Data Grid and allow the user to sort, filter, and navigate through the data, we only have to amend the configuration.</p>
<h2 id="heading-how-to-implement-sorting-filtering-and-pagination">How to Implement Sorting, Filtering, and Pagination</h2>
<p>Here's what we've configured in the Data Grid so far:</p>
<ul>
<li>which fields from the data to display</li>
<li>what data to use</li>
</ul>
<p>To add sorting, filtering, resizable columns, and pagination, we amend the <code>gridOptions</code> configuration:</p>
<pre><code class="lang-javascript">        <span class="hljs-keyword">const</span> gridOptions = {

            <span class="hljs-attr">defaultColDef</span>: {
                <span class="hljs-attr">sortable</span>: <span class="hljs-literal">true</span>,
                <span class="hljs-attr">filter</span>: <span class="hljs-string">'agTextColumnFilter'</span>,
                <span class="hljs-attr">resizable</span>: <span class="hljs-literal">true</span>
            },

            <span class="hljs-attr">pagination</span>: <span class="hljs-literal">true</span>,

            <span class="hljs-attr">columnDefs</span>: columnDefs,
            <span class="hljs-attr">onGridReady</span>: <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span>{renderDataInTheTable(event.api)}
        };
</code></pre>
<p>We can configure columns in AG Grid individually by adding additional properties to the <code>columnDefs</code> objects. Or if the same functionality is required by default in all columns we can configure the <code>defaultColDef</code>.</p>
<p>Here we configure it to be sortable, filterable, and resizable:</p>
<pre><code class="lang-javascript">            defaultColDef: {
                <span class="hljs-attr">sortable</span>: <span class="hljs-literal">true</span>,
                <span class="hljs-attr">filter</span>: <span class="hljs-string">'agTextColumnFilter'</span>,
                <span class="hljs-attr">resizable</span>: <span class="hljs-literal">true</span>
            },
</code></pre>
<p>The default filter we defined for all the columns is the text filter.</p>
<p>To add automatic pagination to the grid, we add the <code>pagination: true</code> property and AG Grid will automatically paginate the data for us.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/sorting-pagination-ez.gif" alt="Data Grid with Sorting, Filtering and Pagination" width="600" height="400" loading="lazy">
<em>Data Grid with Sorting, Filtering and Pagination</em></p>
<h2 id="heading-user-friendly-data-grid">User Friendly Data Grid</h2>
<p>With the above code we have created a User Friendly Data Grid that dynamically fetches the data and adds it to a Data Grid which supports sorting, filtering, and pagination.</p>
<p>Here is the example <a target="_blank" href="https://eviltester.github.io/freecodecampexamples/html-table-to-data-grid/datagrid-index.html">Data Grid HTML Page</a>:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Data Grid Example<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/ag-grid-community/dist/ag-grid-community.min.noStyle.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://unpkg.com/ag-grid-community/dist/styles/ag-grid.css"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://unpkg.com/ag-grid-community/dist/styles/ag-theme-balham.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-id">#data-table</span> {
            <span class="hljs-attribute">height</span>: <span class="hljs-number">500px</span>;
            <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>TODO List<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"data-table"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"ag-theme-balham"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>&gt;</span><span class="javascript">

        <span class="hljs-keyword">const</span> columnDefs = [
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'userId'</span> },
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'id'</span> },
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'title'</span> },
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'completed'</span> },
        ];

        <span class="hljs-keyword">const</span> gridOptions = {

            <span class="hljs-attr">defaultColDef</span>: {
                <span class="hljs-attr">sortable</span>: <span class="hljs-literal">true</span>,
                <span class="hljs-attr">filter</span>: <span class="hljs-string">'agTextColumnFilter'</span>,
                <span class="hljs-attr">resizable</span>: <span class="hljs-literal">true</span>
            },

            <span class="hljs-attr">pagination</span>: <span class="hljs-literal">true</span>,

            <span class="hljs-attr">columnDefs</span>: columnDefs,
            <span class="hljs-attr">onGridReady</span>: <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span>{renderDataInTheTable(event.api)}
        };

        <span class="hljs-keyword">const</span> eGridDiv = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'data-table'</span>);

        <span class="hljs-keyword">new</span> agGrid.Grid(eGridDiv, gridOptions);

        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">renderDataInTheTable</span>(<span class="hljs-params">api</span>) </span>{
            fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/todos'</span>)
                .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
                    <span class="hljs-keyword">return</span> response.json();
                }).then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{
                    api.setRowData(data);
                    api.sizeColumnsToFit();
                })
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h2 id="heading-number-filters">Number Filters</h2>
<p>Since the <code>userId</code> and <code>id</code> columns are numeric, we could make then use a number filter by amending the <code>columnDefs</code>:</p>
<pre><code class="lang-javascript">        <span class="hljs-keyword">const</span> columnDefs = [
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'userId'</span>, <span class="hljs-attr">filter</span>: <span class="hljs-string">'agNumberColumnFilter'</span>},
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'id'</span>, <span class="hljs-attr">filter</span>: <span class="hljs-string">'agNumberColumnFilter'</span>},
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'title'</span> },
            { <span class="hljs-attr">field</span>: <span class="hljs-string">'completed'</span> },
        ];
</code></pre>
<p>Here is the example <a target="_blank" href="https://eviltester.github.io/freecodecampexamples/html-table-to-data-grid/datagrid-number-filters-index.html">Data Grid Number Filters HTML Page</a>.</p>
<p>There are a lot of <a target="_blank" href="https://www.ag-grid.com/javascript-data-grid/column-properties/">configuration options for columns</a> listed in the AG Grid Documentation, for example configuring the width, style, and making the cells editable.</p>
<h2 id="heading-benefits-of-a-data-grid">Benefits of a Data Grid</h2>
<p>For many web sites, a simple HTML table will be a perfectly sensible way to render tabular data. It's fast and easy to understand, and with a little CSS the table can look good for your users.</p>
<p>When your pages become more complex, render more data, or require more interactivity for the user, then it starts to make more sense to use a Data Grid component or library.</p>
<p>Data Grids provide much of the functionality your users need, without having to write a lot of code. In the example presented in this post, we moved from a dynamic table which read the data from an API, to a Data Grid reading from an API with sorting, filtering, pagination, and column resizing. </p>
<p>This is a lot of extra functionality, but our HTML code was the same length and the JavaScript we added was less complicated because the Data Grid did all the work of rendering the data.</p>
<p>Data Grids can handle hundreds of thousands of rows and update quickly so they are often used in real time financial trading systems with prices in cells updating every few milliseconds.</p>
<p>If you are using React, then in addition to <a target="_blank" href="https://www.ag-grid.com/react-data-grid/">AG Grid</a> you could look at <a target="_blank" href="https://mui.com/components/data-grid/">Material UI</a> or <a target="_blank" href="https://react-table.tanstack.com/">React Table</a>. React Table is a 'table' rather than a Data Grid so it requires a little more code initially to render the table.</p>
<p>Both Material UI and React Table are only available for React. AG Grid is framework agnostic and will work with JavaScript, TypeScript, React, Angular, and Vue.</p>
<p>The source code for this post can be <a target="_blank" href="https://github.com/eviltester/freecodecampexamples">found in this Github repo</a> in the folder <a target="_blank" href="https://github.com/eviltester/freecodecampexamples/tree/main/docs/html-table-to-data-grid">docs/html-table-to-data-grid</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Integrate the Material UI Data Grid in React Using Data from a REST API ]]>
                </title>
                <description>
                    <![CDATA[ Material UI's Data Grid is a powerful and flexible data table. It makes it easy for you to display data and perform out of the box functionalities such as editing, sorting, filtering, pagination and more. In this article, we'll discuss why you should... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-integrate-material-ui-data-grid-in-react-using-data-from-a-rest-api/</link>
                <guid isPermaLink="false">66d45e037df3a1f32ee7f7f7</guid>
                
                    <category>
                        <![CDATA[ data ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Datatables ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ deji adesoga ]]>
                </dc:creator>
                <pubDate>Thu, 06 Jan 2022 16:30:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/01/datagrid.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Material UI's Data Grid is a powerful and flexible data table. It makes it easy for you to display data and perform out of the box functionalities such as editing, sorting, filtering, pagination and more.</p>
<p>In this article, we'll discuss why you should use the <strong>Data Grid</strong> in <strong>Material UI</strong> in your project. And then we'll also go through how to install and set up the Data Grid, consume and integrate a RESTful API, and enable pagination as well as sorting and filtering.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-introduction-to-data-grid">Introduction to the Data Grid</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-use-the-material-ui-data-grid">Why use the Material UI Data Grid</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-install-and-setup-react-and-material-ui-data-grid">Installation and Setup of React and Material UI Data Grid</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-api-integration-and-consumption">API Integration and Consumption</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-display-the-api-results-in-the-material-ui-data-grid">Display API Results in Material UI Data Grid</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<p>Watch the video version of this article below, or on my <a target="_blank" href="https://www.youtube.com/watch?v=S_mgSHCWCmA&amp;t=15s">YouTube channel</a>:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/S_mgSHCWCmA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-introduction-to-data-grid">Introduction to Data Grid</h2>
<p>According to the Material UI documentation, <strong>Data Grid</strong> is a</p>
<blockquote>
<p>"<em>fast and extendable React data table and React data grid. It's a feature-rich component available in MIT or Commercial versions</em>".</p>
</blockquote>
<p>Basically, Data Grid in Material UI comes with some features like editing, sorting, filtering, updating, pagination, exports and so on by default.</p>
<p>The team also has future plans of implementing additional features like Excel export, Range selection, Group, Pivot, Aggregation.</p>
<p>For the purpose of this tutorial, we will be implementing some of the features of the Data Grid with a public REST API called <strong>JSONPlaceholder</strong></p>
<h2 id="heading-why-use-the-material-ui-data-grid">Why use the Material UI Data Grid</h2>
<p>There are some important reasons you might want to use the Material UI Data Grid:</p>
<ul>
<li><p>Accessibility</p>
</li>
<li><p>User Interaction</p>
</li>
<li><p>Data Presentation</p>
</li>
</ul>
<h4 id="heading-accessibility">Accessibility</h4>
<p>The Data Grid offers accessibility features such as cell highlighting. That is, every cell is accessible using the keyboard.</p>
<p>It also provides additional features such as keyboard navigation by using certain keys on the keyboard to change the focus of the table cells, along with density properties to determine the row and column height on the table.</p>
<h4 id="heading-user-interaction">User Interaction</h4>
<p>In terms of interaction, the Data Grid provides an inbuilt feature such as row selection by default. This allows the user to select certain rows on mouse click or using certain keyboard shortcuts.</p>
<p>The Data Grid in Material UI supports single and multiple row selection, ability to disable selection certain rows or all rows, checkbox selection and much more.</p>
<h4 id="heading-data-presentation">Data Presentation</h4>
<p>The Data Grid provides an inbuilt feature that allows data to be exported to CSV format.</p>
<p>Also, data can be manipulated by clicking a column header. This will trigger the sorting and filtering functionalities.</p>
<p>Another basic feature that comes by default is scrolling, which does not occur in a normal table by default.</p>
<h2 id="heading-how-to-install-and-setup-react-and-material-ui-data-grid">How to Install and Setup React and Material UI Data Grid</h2>
<p>To create a new project in React, you need to have <a target="_blank" href="https://nodejs.org/en/download/">Node.js</a> installed. This will give us access to npm in our terminal. We can then install and use Create React App using npm to create our project, by running the command below:</p>
<pre><code class="lang-javascript">npm i create-react-app
</code></pre>
<p>The next step is to create a new React project from the terminal by running the command below:</p>
<pre><code class="lang-javascript">npx create-react-app data-grid 
cd data-grid 
npm start
</code></pre>
<p>Above we created a new project called <code>data-grid</code>. Then we navigated into the newly created project directory and started the project with <em>npm.</em></p>
<p>By default, our project will be running on localhost:3000 in the browser.</p>
<p>Finally, we need to install two packages which are <strong>Material UI</strong> and the <strong>Data Grid</strong> using the command below:</p>
<pre><code class="lang-javascript">npm install @mui/x-data-grid @mui/material
</code></pre>
<h2 id="heading-api-integration-and-consumption">API Integration and Consumption</h2>
<p>To integrate our API, we need to create a new file and folder in our src directory that's created for us when we generated our project with Create-React-App. We will call this new folder <strong>Table</strong> and the file will be called <strong>DataGrid.js</strong>.</p>
<p>In the end, our folder structure should look something like this:</p>
<pre><code class="lang-javascript">&gt; src 
    &gt; Table 
        &gt; DataGrid.js 
.gitignore 
package-lock.json 
package.json 
README
</code></pre>
<p>In the DataGrid.js file, we will use a functional component. In this functional component, we will implement some of the following default features in React:</p>
<ul>
<li><p>useState hook</p>
</li>
<li><p>useEffect hook</p>
</li>
<li><p>The Fetch API</p>
</li>
</ul>
<h4 id="heading-the-usestate-hook">The useState Hook</h4>
<p>The <strong>useState</strong> hook in React is an inbuilt function that helps us track state in a functional component.</p>
<h4 id="heading-the-useeffect-hook">The useEffect Hook</h4>
<p>The <strong>useEffect</strong> hook allows us to handle side effects in our functional component. Some of these side effects could include things like updating the DOM, fetching data from a RESTful API, timer events, and so on.</p>
<h4 id="heading-the-fetch-api">The Fetch API</h4>
<p>The <strong>Fetch API</strong> in JavaScript allows web browsers to make HTTP requests to web servers. The request can be of any APIs that send and receive data in JSON or XML format.</p>
<p>Now that we've explored the concept of hooks and the Fetch API, let's generate a boilerplate functional component in our DataGrid.js file:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">const</span> DataGrid= <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DataGrid
</code></pre>
<p>The next step is to consume the REST API from <a target="_blank" href="https://jsonplaceholder.typicode.com/posts">JSON placeholder</a>.</p>
<p>To do that, the first thing we need to do is to import the useState and useEffect hooks:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
</code></pre>
<p>Then we create a variable using the useState hook:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [tableData, setTableData] = useState([])
</code></pre>
<p>The <strong>tableData</strong> above serves as a getter, while the <strong>setTableData</strong> serves as a setter.</p>
<p>Finally, to access our data we will use the useEffect hook and the Fetch API:</p>
<pre><code class="lang-jsx">useEffect(<span class="hljs-function">() =&gt;</span> {
  fetch(<span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span>)
    .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> data.json())
    .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> setTableData(data))
}, [])
 <span class="hljs-built_in">console</span>.log(tableData)
</code></pre>
<p>Above, we can see that inside the useEffect hook, we did three things:</p>
<ul>
<li><p>First, inside the useEffect hook, we used Fetch to consume the JSON placeholder REST API</p>
</li>
<li><p>Then we converted the response we got into JSON format</p>
</li>
<li><p>Lastly, we passed the data from our response to the setter we created earlier called setTableData</p>
</li>
</ul>
<p>To be sure we got the right response, we logged the data we got into the console. To see the results in the console, we need to import our <strong>DataGrid.js</strong> inside our <strong>App.js</strong> file:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> DataGrid <span class="hljs-keyword">from</span> <span class="hljs-string">'./Table/DataGrid'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">DataGrid</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Then we get the result below, which consists of a list of 100 objects in an array:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/console.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>JSON Data in the Console</em></p>
<h2 id="heading-how-to-display-the-api-results-in-the-material-ui-data-grid">How to Display the API Results in the Material UI Data Grid</h2>
<p>To display our API results in the Material UI Data Grid, we need to import the Data Grid package into our DataGrid.js file:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { DataGrid } <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/x-data-grid'</span>
</code></pre>
<p>We then set up the configuration for the header section of our Data Grid table:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> columns = [
  { <span class="hljs-attr">field</span>: <span class="hljs-string">'id'</span>, <span class="hljs-attr">headerName</span>: <span class="hljs-string">'ID'</span> },
  { <span class="hljs-attr">field</span>: <span class="hljs-string">'title'</span>, <span class="hljs-attr">headerName</span>: <span class="hljs-string">'Title'</span>, <span class="hljs-attr">width</span>: <span class="hljs-number">300</span> },
  { <span class="hljs-attr">field</span>: <span class="hljs-string">'body'</span>, <span class="hljs-attr">headerName</span>: <span class="hljs-string">'Body'</span>, <span class="hljs-attr">width</span>: <span class="hljs-number">600</span> }
]
</code></pre>
<p>As you can see above, it is in an array of objects and it contains an <strong>id</strong>, <strong>title</strong> and a <strong>body,</strong> which is in accordance with the results we got from our REST API.</p>
<p>Finally, we bring in the DataGrid component into our return statement:</p>
<pre><code class="lang-jsx">&lt;div style={{ <span class="hljs-attr">height</span>: <span class="hljs-number">700</span>, <span class="hljs-attr">width</span>: <span class="hljs-string">'100%'</span> }}&gt;
     <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">DataGrid</span>
       <span class="hljs-attr">rows</span>=<span class="hljs-string">{tableData}</span>
       <span class="hljs-attr">columns</span>=<span class="hljs-string">{columns}</span>
       <span class="hljs-attr">pageSize</span>=<span class="hljs-string">{12}</span>
     /&gt;</span></span>
   &lt;/div&gt;
</code></pre>
<p>Above, we have three properties inside the DataGrid component:</p>
<ul>
<li><p>The first one is the <strong>rows</strong> property. What we did with the row property was to pass in the results we got from our REST API, which is contained in the getter called tableData</p>
</li>
<li><p>The second property is called <strong>columns</strong>. This is the array of objects that contains the header of our DataGrid that include the id, title and body.</p>
</li>
<li><p>The last property is the pageSize. This helps us to set a limit to the amount of data that can be displayed at once. As you can see, we set this to 12 – the rest of the result is then paginated by default.</p>
</li>
</ul>
<p>In the end, our DataGrid.js file should look something like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { DataGrid } <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/x-data-grid'</span>

<span class="hljs-keyword">const</span> columns = [
  { <span class="hljs-attr">field</span>: <span class="hljs-string">'id'</span>, <span class="hljs-attr">headerName</span>: <span class="hljs-string">'ID'</span> },
  { <span class="hljs-attr">field</span>: <span class="hljs-string">'title'</span>, <span class="hljs-attr">headerName</span>: <span class="hljs-string">'Title'</span>, <span class="hljs-attr">width</span>: <span class="hljs-number">300</span> },
  { <span class="hljs-attr">field</span>: <span class="hljs-string">'body'</span>, <span class="hljs-attr">headerName</span>: <span class="hljs-string">'Body'</span>, <span class="hljs-attr">width</span>: <span class="hljs-number">600</span> }
]

<span class="hljs-keyword">const</span> DataGrid = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> [tableData, setTableData] = useState([])

  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetch(<span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span>)
      .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> data.json())
      .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> setTableData(data))

  }, [])

  <span class="hljs-built_in">console</span>.log(tableData)

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">height:</span> <span class="hljs-attr">700</span>, <span class="hljs-attr">width:</span> '<span class="hljs-attr">100</span>%' }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">DataGrid</span>
        <span class="hljs-attr">rows</span>=<span class="hljs-string">{tableData}</span>
        <span class="hljs-attr">columns</span>=<span class="hljs-string">{columns}</span>
        <span class="hljs-attr">pageSize</span>=<span class="hljs-string">{12}</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DataGrid
</code></pre>
<p>The results in the browser should also look like the image we have below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/grid.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Data Grid Table Result</em></p>
<p>One awesome thing to note in the result of our image above is that, we have an out-of-the-box sorting and filtering functionality when we click on the header section(<em>id, title, body</em>) of our data table.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we learned about DataGrid in Material UI, React Hooks, REST API consumption and much more.</p>
<p>Also, the link to the code of this article can be found on <a target="_blank" href="https://github.com/desoga10/data-grid">GitHub</a>.</p>
<p>If you enjoyed this article, show your support by subscribing to my <a target="_blank" href="https://www.youtube.com/TheCodeAngle">YouTube channel</a> where I create awesome tutorials on web development technologies like JavaScript, React, Angular, Node.js, and more.</p>
<p>If you have any feedback or question on this post or other programming related questions, you can find me on Twitter <a target="_blank" href="https://twitter.com/thecodeangle">@thecodeangle</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to create responsive tables with pure CSS using Grid Layout Module ]]>
                </title>
                <description>
                    <![CDATA[ By Shingo Nakayama TL;DR The most popular way to display a collection of similar data is to use tables, but HTML tables have the drawback of being difficult to make responsive. In this article, I use CSS Grid Layout Module and CSS Properties (and no ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/https-medium-com-nakayama-shingo-creating-responsive-tables-with-pure-css-using-the-grid-layout-module-8e0ea8f03e83/</link>
                <guid isPermaLink="false">66d460ee57503cc72873ded6</guid>
                
                    <category>
                        <![CDATA[ css properties ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Datatables ]]>
                    </category>
                
                    <category>
                        <![CDATA[ flexbox ]]>
                    </category>
                
                    <category>
                        <![CDATA[ grid layout ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 26 Feb 2019 06:17:06 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*CthvMCprY75MLB_q8BygXg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Shingo Nakayama</p>
<h3 id="heading-tldr">TL;DR</h3>
<p>The most popular way to display a collection of similar data is to use tables, but HTML tables have the drawback of being difficult to make responsive.</p>
<p>In this article, I use CSS Grid Layout Module and CSS Properties (and no Javascript) to layout tables that wrap columns depending on screen width, which further changes to a card based on layout for small screens.</p>
<p>For the impatient, look at the following pen for a prototypical implementation.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/ShingoNakayama/embed/LMLeRZ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<h3 id="heading-a-little-history-of-responsive-html-tables">A Little History of Responsive HTML Tables</h3>
<p>Responsive tables aren’t a new topic, and there are many solutions that have already been proposed. <a target="_blank" href="https://css-tricks.com/responsive-data-table-roundup/">“Responsive Table Data Roundup”</a> first published in 2012 by Chris Coyier, has things summarized very neatly (including a 2018 update).</p>
<p><a target="_blank" href="https://hashnode.com/post/really-responsive-tables-using-css3-flexbox-cijzbxd8n00pwvm53sl4l42cx">“Really Responsive Tables using CSS3 Flexbox”</a> by Vasan Subramanian shows an idea of wrapping columns, implemented with Flexbox.</p>
<p>Even though many interesting ideas have been proposed, libraries like <a target="_blank" href="https://getbootstrap.com/docs/4.0/content/tables/#responsive-tables">bootstrap</a> opt for horizontal scrolling for small screens.</p>
<p>As we now have CSS Grid, I think we could have a better common alternative to horizontal scrolling.</p>
<h3 id="heading-html-tables">HTML Tables</h3>
<p>Starting with the basics, a table in HTML is a layout format for displaying collections of items through a matrix of rows and columns. Items are laid out in rows, with the same data attributes in the same columns, with the rows often sorted with one or more sortable attributes. The format gives you a birds-eye view to quickly grasp and examine large quantities of data.</p>
<p>For example, here’s a hypothetical table of purchase order details, that you may see in a purchasing application.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*B78yFFUVc1X8uEp_gVLcNw.png" alt="Image" width="800" height="57" loading="lazy">
<em>Table of purchase order details</em></p>
<p>An item, in this case, is a purchase order detail, that has attributes such as part number, part description, etc.</p>
<p>When using HTML tables, the layout of the data is hardcoded as rows and columns (e.g. <code>&lt;tr&gt;</code> and <code>&lt;td&gt;</code>). This may be sufficient for usage by a screen that fits the whole table width, but in reality, this does not apply for the myriad of devices that exist today. In terms of hacks, you can alter the display property of tables and use any layout you can do with CSS in general, but that doesn’t seem semantically correct.</p>
<h3 id="heading-tables-redefined-collection-of-items">Tables Redefined (= Collection of Items)</h3>
<p>Let’s start by redefining how table data should be expressed in HTML.</p>
<p>As stated earlier, since table data is essentially an ordered collection of items, it seems natural to use ordered lists. Also, since tables are often used to supplement textual descriptions, it seems natural to enclose this in a section, but this would depend on the context of how the table data is being used.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
 <span class="hljs-tag">&lt;<span class="hljs-name">ol</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- The first list item is the header of the table --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>#<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-comment">&lt;!-- Enclose semantically similar attributes as a div hierarchy --&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Part Number<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Part Description<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
   ...
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- The rest of the items in the list are the actual data --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-comment">&lt;!-- Group part related information--&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>100-10001<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Description of part<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  ...
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
 ...
 <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
</code></pre>
<p>Vanilla <code>&lt;div&gt;</code>'s are used to express item attributes since HTML5 does not define an appropriate tag for this. The key here is to express semantically similar attributes as a hierarchy of <code>&lt;div&gt;</code>'s. This structure will be used when defining how the data should be laid out. I will come back to this in the next section on the topic of styling.</p>
<p>As for the actual data inside the <code>&lt;div&gt;</code> element, the first item in the list is the header, and the rest of the items are the actual data.</p>
<p>Now, it’s time to start talking about styling the items with CSS Grid.</p>
<h3 id="heading-styling-item-collections">Styling Item Collections</h3>
<p>The basic idea here is to display all attributes of the item as a normal table, display width permitting. This layout has the luxury of being able to see as many items (rows) as possible.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*6sZipUcqB3hru4Q5r0kORw.png" alt="Image" width="800" height="48" loading="lazy">
<em>Full Table</em></p>
<p>When the width of the display becomes narrower, some attributes are stacked vertically, in order to save horizontal space. The choice of stacking attributes should be based on:</p>
<ol>
<li>Do the attributes make sense when stacked vertically? and,</li>
<li>When stacked vertically, does it save horizontal space?</li>
</ol>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*llLsnXzdnBBfMRPqoKNBmw.png" alt="Image" width="800" height="110" loading="lazy">
<em>Wrapping Table 1. Start by wrapping columns that need little width, and give the other columns space</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*DdQ-n4VzeGU1EzhRKdHj8w.png" alt="Image" width="800" height="116" loading="lazy">
<em>Wrapping Table 2. Wrap “Part Description”, to be able to see the description</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*ys0ukWXXtbWhVyXTD9E0Zw.png" alt="Image" width="800" height="145" loading="lazy">
<em>Wrapping Table 3. Further wrap “Vendor Name”</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*-ik1zA0LDXzWib7Ux-4EpQ.png" alt="Image" width="800" height="267" loading="lazy">
<em>Wrapping Table 4. Wrap vendor related information under part related information</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*sEvQQjZoux7PEii3JQpCRg.png" alt="Image" width="747" height="353" loading="lazy">
<em>Wrapping Table 5. Fully wrapped</em></p>
<p>When the width further shrinks to the size of a mobile device, each item is displayed as a card. This layout has redundancy because the attribute names are repeatedly displayed on each card, and has the least glanceability, but does not compromise usability (e.g. horizontal scrolling, super small text, etc).</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*jI0hhzrpYpjbO3-fGh8IWA.png" alt="Image" width="695" height="485" loading="lazy">
<em>Two Column Card Layout</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*XCCcicUngRBcBaKyETC4vg.png" alt="Image" width="445" height="722" loading="lazy">
<em>One Column Card Layout</em></p>
<p>Now let’s dive into the details.</p>
<h4 id="heading-styling-step-1-full-table">Styling Step 1: Full Table</h4>
<p>Here’s a visual summary of how things will be implemented with CSS Grid.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*uA9PfcQ9JCzY54mH7p_v-A.png" alt="Image" width="755" height="344" loading="lazy">
<em>Grid containers</em></p>
<p>In order to make columns wrap, multiple grid containers are defined as a hierarchy. The red box is a grid container for each row, and the blue box is a container for each column group that wraps.</p>
<p>Let’ s start by setting the list as a grid container by defining a class called <code>.item-container</code> and applying it to the <code>&lt;li&gt;</code>(the red box).</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.item-container</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">2em</span> <span class="hljs-number">2em</span> <span class="hljs-number">10</span>fr <span class="hljs-number">2</span>fr <span class="hljs-number">2</span>fr <span class="hljs-number">2</span>fr <span class="hljs-number">2</span>fr <span class="hljs-number">5em</span> <span class="hljs-number">5em</span>;
}
</code></pre>
<p>The number of explicit columns specified with <code>grid-template-columns</code> is nine, which is the number of top-level <code>&lt;div&gt;</code>'s, directly  under <code>&lt;li&gt;</code>.</p>
<p>The column’s width is defined in relative length to make the columns wrap. The actual fraction has to be fine-tuned, based on the content.</p>
<p>The columns that don’t wrap are defined in absolute length to maximize width usage for the wrapping columns. In the purchase order details example, the second column is a two-digit Id, so I set the width to double that size of 2 m’s.</p>
<p>Next, we define another grid container called <code>.attribute-container</code> and apply it on all intermediate <code>&lt;div&gt;</code>’s under the list (the blue box).</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.attribute-container</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(auto-fit, minmax(var(--column-width-min), <span class="hljs-number">1</span>fr));
    }
</code></pre>
<p>The minimum column width for all grid items under <code>.attribute-container</code> is specified with a CSS variable called <code>--column-width-min</code>(more on this later) using the <code>minmax</code> function, with the maximum set to take the rest of the space (e.g. one fraction). Since <code>grid-template-columns</code> are <code>repeat</code>ed, available horizontal space will be split into the maximum number of columns that could take at least <code>--column-width-min</code>, and the rest of the columns would go to the next line. The column’s width will be stretched if there is excess horizontal space because the <code>repeat</code> is <code>auto-fit</code>ed.</p>
<h4 id="heading-styling-step-2-wrapping-table">Styling Step 2: Wrapping Table</h4>
<p>Next, <code>--column-width-min</code> needs to be specified independently for each column in order to wrap. Just to be clear, the variables need to be specified in order for the full table to render properly as well. To do this, a class is set for each <code>.attribute-container</code>, and a different <code>--column-width-min</code> is specified for each class scope.</p>
<p>Let’s take a look at the HTML where <code>.part-id</code> is applied,</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribute-container part-id"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Part Number<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Part Description<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>and the CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.part-id</span> {
    <span class="hljs-attribute">--column-width-min</span>: <span class="hljs-number">10em</span>;
}
</code></pre>
<p>This specific grid container will have two columns, as long as the available width is wider than 10em for each grid item (e.g. the grid container is wider than 20em). Once the grid container’s width becomes narrower than 20em, the second grid item will go to the next row.</p>
<p>When we combine CSS properties like this, we need only one grid container <code>.attribute-container</code>, with the details changing where the class is applied.</p>
<p>We can further nest <code>.attribute-container</code>s, to have multiple levels of wrapping with different widths, as in the following exert.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribute-container part-information"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribute-container part-id"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribute"</span> <span class="hljs-attr">data-name</span>=<span class="hljs-string">"Part Number"</span>&gt;</span>Part Number<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribute"</span> <span class="hljs-attr">data-name</span>=<span class="hljs-string">"Part Description"</span>&gt;</span>Part Description
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribute-container vendor-information"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribute"</span>&gt;</span>Vendor Number<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribute"</span>&gt;</span>Vendor Name<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
.part-information {
    --column-width-min: 10em;
}
.part-id {
    --column-width-min: 10em;
}
.vendor-information {
    --column-width-min: 8em;
}
</code></pre>
<p>All of the above is enclosed in the following media query. The actual breakpoint should be selected based on the width necessary when your table is wrapped to the extreme.</p>
<pre><code>@media screen and (min-width: <span class="hljs-number">737</span>px) {
...
}
</code></pre><h4 id="heading-styling-step-three-card-layout">Styling Step Three: Card Layout</h4>
<p>The card layout will look like a typical form with attribute names in the first column and attribute values in the second column.</p>
<p>To do this, a class called <code>.attribute</code> is defined and applied to all leaf <code>&lt;div&gt;</code> tags under the <code>&lt;li&gt;</code>.</p>
<pre><code class="lang-js">.attribute {
    <span class="hljs-attr">display</span>: grid;
    grid-template-columns: minmax(<span class="hljs-number">9</span>em, <span class="hljs-number">30</span>%) <span class="hljs-number">1</span>fr;
}
</code></pre>
<p>The attribute names are taken from a custom attribute of the leaf  <code>&lt;div&gt;</code> called <code>data-name</code>, for example <code>&lt;div class=”attribute” data-name="Part Number"&gt;</code>, and a pseudo-element is created. The pseudo-element will be subject to the grid container’s layout.</p>
<pre><code class="lang-js">.attribute::before {
    <span class="hljs-attr">content</span>: attr(data-name);
}
</code></pre>
<p>The first item in the list is the header and does not need to be displayed.</p>
<pre><code class="lang-js"><span class="hljs-comment">/* Don't display the first item, since it is used to display the header for tabular layouts*/</span>
.collection-container&gt;li:first-child {
    <span class="hljs-attr">display</span>: none;
}
</code></pre>
<p>And finally, the cards are laid out in one column for mobile devices, but two for screens with a little bit more width, but not enough for displaying a table.</p>
<pre><code><span class="hljs-comment">/* 2 Column Card Layout */</span>
@media screen and (max-width: <span class="hljs-number">736</span>px) {
    .collection-container {
        <span class="hljs-attr">display</span>: grid;
        grid-template-columns: <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr;
        grid-gap: <span class="hljs-number">20</span>px;
    }
...
}
<span class="hljs-comment">/* 1 Column Card Layout */</span>
@media screen and (max-width:<span class="hljs-number">580</span>px) {
    .collection-container {
        <span class="hljs-attr">display</span>: grid;
        grid-template-columns: <span class="hljs-number">1</span>fr;
    }
}
</code></pre><h3 id="heading-finishing-notes">Finishing Notes</h3>
<p>Accessibility is an area that wasn’t considered at all and may have some space for improvement.</p>
<p>If you have any ideas or second thoughts, please feel free to comment!</p>
<p>And of course, thanks for reading.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
