March 14, 2018

Responsive Table

A mobile-friendly table solution, which persists headers for each table-cell on mobile devices.

I took a stab at a responsive table during a recent hackathon project. It turned out pretty well, so I thought I’d share.

tl;dr: Here’s the demo and code:

Demo and Code

Scrolling Example of a Responsive Table


Here’s a typical data table with column headers at the top and rows below.

Horizontal Table Layout on Desktop

On mobile devices the orientation changes from horizontal to vertical, and each cell is prepended with its respective table header as a label.

Vertical Table Layout on Mobile

I was going for a really clean look where labels and cells would line up with the previous row, but I also wanted it to be fluid, so I could just plug it into any site without having to adjust widths in the future.

There are a few things at play here:

Demo on CodePen

Resize your browser to see it in action

See the Pen Mobile Friendly Table by Jeremy Church (@jeremychurch) on CodePen.

HTML

<table class='js-table-data'>
  <thead>
    <tr>
      <th>Company</th>
      <th>Location</th>
      <th data-label='Desc'>Description</th>
    </tr>
  </thead>
  <tr>
    <td>Acme Company, LLC</td>
    <td>Denver, CO</td>
    <td>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos necessitatibus obcaecati quibusdam.</td>
  </tr>
</table>

CSS

@media screen and (max-width: 767px) {
  thead { display: none; }
  tr {
    display: block;
    position: relative;
    padding: 1.2em 0; }
  tr:first-of-type { border-top: 1px solid #ccc; }
  td { display: table-row; }
  td:before {
    content: attr(data-label);
    display: table-cell;
    font-weight: bold;
    padding: 0.2em 0.6em 0.2em 0;
    text-align: right; }
  td:last-child:after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    border-bottom: 1px solid #ccc; }
}

JavaScript

$(document).ready(function(){
  $('.js-table-data').each(function(){
    table = $(this);
    tableRow = table.find('tr');
    table.find('td').each(function(){
      tdIndex = $(this).index();
      if ($(tableRow).find('th').eq(tdIndex).attr('data-label')){
        thText = $(tableRow).find('th').eq(tdIndex).data('label');
      } else {
        thText = $(tableRow).find('th').eq(tdIndex).text();
      }
      $(this).attr('data-label', thText + ':');
    });
  });
});

Not sure how to include JavaScript?

Save the above JavaScript to a file (e.g. responsive-table.js), then add the following to your HTML just before the closing </body> tag (includes jQuery library as well).

<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
<script src='responsive-table.js'></script>

</body>

Different Headers for Mobile

If you need to modify a header on mobile devices for whatever reason (e.g. “Description” could be shortened to “Desc”), you can manually add data-label to a specific <th>, and the JavaScript will grab that instead of the inner text.

<th data-label='Desc'>Description</th>

CSS-Only Solution

You may not need to include the JavaScript. If your table rows are generated within a loop, AND you don’t have a lot of different tables with different headers, then you can manually add the data attributes to each <td> within the loop, and omit the JavaScript.

<td data-label='Name'>Name</td>

Potential issues for CSS-only solution:

Resources / Inspiration