Responsive HTML table with repeating headers each row

Viewed 1793

I am working on a HTML data table and I want it to show on desktop as it is and on mobile with repeating headers. How can I accomplish this?

Requirement:

On desktop

ID | Name | Age
_______________
1  | Jake | 23
2  | Dave | 45

On mobile

ID   | 1
Name | Jake
Age  | 23 
_______________
ID   | 2
Name | Dave
Age  | 45 

My table code:

<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Age</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1</td>
            <td>Jake</td>
            <td>23</td>
        </tr>
        <tr>
            <td>2</td>
            <td>Dave</td>
            <td>45</td>
        </tr>
    </tbody>
</table>
2 Answers

There are several available, responsive table solutions including this simple, CSS-only pattern:

data-label attribute :

First, we’ll add a data-label attribute to each data cell with a value that represents that column’s name. That will be used for labeling purposes in the responsive layout.
In smaller viewports the <tr> and <td> elements will display as block-level and not as table rows and cells. And the ::before pseudo-class now serves as a label.

body {
  font-family: "Open Sans", sans-serif;
  line-height: 1.25;
}

table {
  border: 1px solid #ccc;
  border-collapse: collapse;
  margin: 0;
  padding: 0;
  width: 100%;
  table-layout: fixed;
}

table caption {
  font-size: 1.5em;
  margin: .5em 0 .75em;
}

table tr {
  background-color: #f8f8f8;
  border: 1px solid #ddd;
  padding: .35em;
}

table th,
table td {
  padding: .625em;
  text-align: center;
}

table th {
  font-size: .85em;
  letter-spacing: .1em;
  text-transform: uppercase;
}

@media screen and (max-width: 600px) {
  table {
    border: 0;
  }

  table caption {
    font-size: 1.3em;
  }
  
  table thead {
    border: none;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
  }
  
  table tr {
    border-bottom: 3px solid #ddd;
    display: block;
    margin-bottom: .625em;
  }
  
  table td {
    border-bottom: 1px solid #ddd;
    display: block;
    font-size: .8em;
    text-align: right;
  }
  
  table td::before {
    /*
    * aria-label has no advantage, it won't be read inside a table
    content: attr(aria-label);
    */
    content: attr(data-label);
    float: left;
    font-weight: bold;
    text-transform: uppercase;
  }
  
  table td:last-child {
    border-bottom: 0;
  }
}
<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Age</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-label="ID">1</td>
            <td data-label="Name">Jake</td>
            <td data-label="Age">23</td>
        </tr>
        <tr>
            <td data-label="ID">2</td>
            <td data-label="Name">Dave</td>
            <td data-label="Age">45</td>
        </tr>
    </tbody>
</table>

Data tables don't do so well with responsive design unfortunately, you need to work hard with CSS

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>Name</th>
      <th>Age</th>
    </tr>
  </thead>
<tbody>
  <tr>
      <td>1</td>
      <td>Jake</td>
      <td>23</td>
  </tr>
  <tr>
      <td>2</td>
      <td>Dave</td>
      <td>45</td>
  </tr>
</tbody>
</table>

Normal CSS would be (desktops):

/* 
Generic Styling, for Desktops/Laptops 
*/
table { 
  width: 100%; 
  border-collapse: collapse; 
}
/* Zebra striping */
tr:nth-of-type(odd) { 
  background: #eee; 
}
th { 
  background: #333; 
  color: white; 
  font-weight: bold; 
}
td, th { 
  padding: 6px; 
  border: 1px solid #ccc; 
  text-align: left; 
}

Target the media query that you need -special thanks to Chris Coyier

@media only screen and (max-width: 760px),
(min-device-width: 768px) and (max-device-width: 1024px)  {

/* Force table to not be like tables anymore */
table, thead, tbody, th, td, tr { 
    display: block; 
}

/* Hide table headers (but not display: none;, for accessibility) */
thead tr { 
    position: absolute;
    top: -9999px;
    left: -9999px;
}

tr { border: 1px solid #ccc; }

td { 
    /* Behave  like a "row" */
    border: none;
    border-bottom: 1px solid #eee; 
    position: relative;
    padding-left: 50%; 
}

td:before { 
    /* Now like a table header */
    position: absolute;
    /* Top/left values mimic padding */
    top: 6px;
    left: 6px;
    width: 45%; 
    padding-right: 10px; 
    white-space: nowrap;
}

/*
Label the data
*/
td:nth-of-type(1):before { content: "First Name"; }
td:nth-of-type(2):before { content: "Last Name"; }
td:nth-of-type(3):before { content: "Job Title"; }
td:nth-of-type(4):before { content: "Favorite Color"; }
td:nth-of-type(5):before { content: "Wars of Trek?"; }
td:nth-of-type(6):before { content: "Secret Alias"; }
td:nth-of-type(7):before { content: "Date of Birth"; }
td:nth-of-type(8):before { content: "Dream Vacation City"; }
td:nth-of-type(9):before { content: "GPA"; }
td:nth-of-type(10):before { content: "Arbitrary Data"; }
}

Is not perfect, the idea is that you use this as a solution for your needs. Please visit the CSS-Tricks Responsive tables

Related