Responsive Table Layout with CSS Grid

Making tables responsive to screen size has always been a bit an issue with no perfect solution for all situations.

One option is to hide some less important data as the screen size gets smaller, and then allow the user to expand the data somehow if they want to see everything.

Or you could set the table to scroll horizontally if the screen size is too small.

These options may be necessary for big complex tables of lots of data, but if you are dealing with a simple table, I find that using CSS grid offers an elegant solution.

See the Pen Simple Responsive Table Layout with CSS Grid by Lisa Catalano (@lisa_c) on CodePen.



In this example I have two sections that are grids and use the same layout which is set up with the term-grid class. The header section is a grid, and each line in the data section is a grid. Please note that I’m using Vue.js to display the data and keep the html clean, but it is unrelated to the grid. If I was not using Vue, each line of data would be repeated with its own grid. Below is an example of what the HTML for one definition without Vue would look like.

<div class="term-grid">
  <label>Lorem</label>
  <div class="definition">ipsum dolor sit amet consectetur adipisicing</div>
  <div class="alternate">something</div>
</div>

The important CSS is to add display: grid to the container that you want to be a grid. In my example, this is done with the class term-grid. You also want to set up the size of each column in the grid using grid-template-columns. I am using fractional units to set up the different column widths. Using fractional units means that the columns will grow and shrink proportionally as the screen-size changes. The grid-gap is simply the gap in between the columns.

.term-grid {
  display: grid;
  grid-template-columns: 1fr 4fr 1fr;
  grid-gap: 2em;
}

When the user is on a small screen, you can easily change the layout to be a column of data instead of a row. There are different ways to achieve this, but the way I handle it is to change the grid-template-columns property to just be 1fr. Each of the data pieces in the grid will take up the full width of the screen, or to be more accurate, the full width of its parent container.

@media (max-width: 600px) {
  .term-grid {
    grid-template-columns: 1fr;
    grid-gap: 0.5em;
  }

  .grid-header {
    display: none;
  }

  .alternate {
    margin-top: -10px;
    font-style: italic;
    order: 1;
  }
  
  .definition {
    order: 2;
  }
}

I’m also hiding the headers and changing the order and styles slightly of the second and third data cells. This is not going to be something you always want to do, but because the 3rd column is optional, I wanted it to show under the term and be italics so it doesn’t look like part of the definition.

See the Pen Simple Responsive Table Layout with CSS Grid by Lisa Catalano (@lisa_c) on CodePen.



I’m embedding the Pen a second time with code to force the screen to be smaller, so you can see the mobile version. If it not showing for you, you can open the pen in its own tab and play with the screen size on your own.

The code that is defining the grid and the small changes for mobile are really just a few lines, and I really like this solution for simple tables of data.

Vertical Centering

Centering things vertically used to be more difficult, but these days with flexbox it is very easy.
  display: flex;
  justify-content: center; /* Horizontal Centering */
  align-items: center;     /* Vertical Centering */

You simply need to set the display property for the parent container to flex, and then set align-items: center. The above properties all belong to the parent item, and not the item you are actually trying to center.

In my example I am centering the box on the page, and I am also centering the text in the box. The horizontal centering is accomplished with justify-content: center. Before flexbox you could use text-align: center and that is still an option.

See the Pen Vertical Centering by Lisa Catalano (@lisa_c) on CodePen.


Please note that another property that comes in to play when aligning things in flexbox is the flex-direction. The default direction is row which means that the direction is going horizontally across the page. I did not need to set it in my pen, but I added it because the direction is important. You can also set the direction to column. If it was set to column the properties you set to center things flip. justify-content: center would make the content be centered vertically (and then align-items: center would center things horizontally.

novalidate Form option

This is just a quick tip, but something I’ve recently discovered as a nice option for development work.

Modern browsers do some validation of fields on forms depending on your markup.
For example:
<input type="email" name="email" id="email" required>
will do some basic validation ensuring that the user inputs an email address on not just some string of text. Also the required will cause the browser to not submit the form until the user types something in that field.

These browser validations are very nice and I generally add them. However, you may want to make sure that the fields are validated with client and/or server code also. If you do use these HTML5 options but want to test either your front-end or back-end validation code, it can be a pain to do so, because the browser catches the problems first. Until recently, I thought you had to remove the required from the tag or even change the input type away from email, however there is a quicker way.

Just add novalidate to your form tag and the browser validation will be turned off. This is a simpler solution and easy to remove if you want it turned on for production code.

<form action="/something" method="get" novalidate>