Start a personal dev blog on your domain for free with Hashnode and grow your readership.
Get Started

Really Responsive Tables using CSS3 Flexbox

For a long time, I've been looking for a really responsive way to handle tables in a browser. Some technique that lets tables smoothly adapt to many screen sizes, not just desktop vs. mobile. Having found none, I created my own using <div>s and CSS3 Flexbox, and here it is.

Why tables

  1. Tables are a very nice way to show a list of very similar items. People just get it, when it's a table.
  2. The alignment of fields in columns is very helpful in getting a feel for the values, how they differ or are similar across rows.
  3. Using cards like this list of JIRA issues is an option, still, it doesn't feel as good as a table when the number of rows / columns is large such as this bugzilla bug list.

Problems with conventional tables

  1. If they are fixed width, they don't let the user take advantage of a larger screen size.
  2. If they are not fixed width, cells can wrap on smaller screens. But only cells with long content wrap, and you can get uneven sized rows. This is an eyesore.
  3. If you set overflow: hidden and add ellipsis to restrict all rows to one line, on very small screens, you end up seeing almost nothing.

There are many solutions proposed for responsive tables at this post: 10+ Solutions for Responsive Data Tables. But I'm not happy. They're all binary solutions (i.e., Desktop vs. Mobile -- all or none). There are no solutions that address what I really want, something smoothly adapting to varying screen widths -- really responsive.

What I want: really responsive tables

  1. Maximisation of real-estate is important. Minimum white space.
  2. Wrapping cells is not OK. Wrapping a row is ok, as long as all rows are laid out the same way.
  3. No horizontal scrollbar, ever.
  4. Fields should be aligned, otherwise, it's not a table.
  5. Optimum layout for any screen size, that is, really responsive!

Flexbox to the rescue

I got enamored by CSS Flexbox, since it was faintly reminiscent of GridBagLayout (no, don't go there). This was my first exposure to fluid layouts, circa 1996.

If you are not familiar with Flexbox, please read A Visual Guide to CSS3 Flexbox Properties or this answer by @fazlerocks . It's is a pre-requisite to follow the rest of this story.

OK, now that you're familiar with Flexbox, we can discuss a few approaches to achieve really responsive tables using Flexbox <div>s instead of HTML <table>s. Let's start with a table which looks like this on large screens:

title here

Plain Wrap

This is a simplistic approach using flex: wrap. When there isn't enough horizontal space, a row wraps naturally. The right most columns go to the next line, one after the other.

Plain Wrap - Small

The CodePen for this approach is at Responsive Tables using Flexbox (Plain Wrap). Do play with it, check out its behaviour at various screen sizes.

Nested Wrap

Although the Plain Wrap approach is very simple to implement, the columns visually interfere with one another vertically. To address this, we nest multiple divs so that related cells stay together. The border colors show the nesting below.


CodePen: Responsive Tables using Flexbox (Nested Wrap).

Controlled Wrap

We still don't have control on which cells wrap when. Some times they look good, some other times, fields still interfere. I'd have really liked to see First Name and Last Name vertically stacked when displaying a row as two lines. This is because flex: wrap has its own mind and decides when to wrap what.

To have exact control we need to switch to flex-direction: column on the wrappers, whenever we want. To achieve this, we need media queries that change the flex-direction as the screen size shrinks.


For the same screen width as the previous example, this looks much better. Note that now we even have the numeric columns right-aligned, and they look good too!

CodePen: Really Responsive Tables using Flexbox (controlled wrap).

Advanced Example

Controlled Wrap gives us what we want, but we made some big assumptions about uniformity of field widths. Life is usually not this simple. In reality, we encounter different field widths, some with fixed width, some variable. We have to deal with each column individually and lay it out to perfection, maybe like this:

Single line: Advanced Large screen

3-line rows: title here

5-line rows: Advanced Mobile View

Really responsive, finally.

Here's the CodePen: Really Responsive Tables using CSS Flexbox (complex).

To implement something on your own like this, it's a bit of a work, especially to decide how the columns are laid out at different screen sizes. But, believe me, it's worth it.

GCat's photo

Great work! I'm wondering if it's possible, using this or something similar, to have the header row (rows if wrapped) stay pegged, so for large datasets you can scroll vertically and always have the headers visible.

GCat's photo

Flexbox to the rescue again. Just use separate divs for the header row container and the body rows, then html, body{height: 100%;} body{display: flex; flex-direction: column; justify-content:flex-start} container-fluid{overflow-y: auto}. Header row column alignment will have to be tweaked to account for scrollbar somehow, when present.

Gultekin Irengun's photo

I think this is a must because when there is no header in view the table info makes no sense especially when they are laid out like that in smaller screens. I need to see this working with dynamic table where columns can be added or taken out and order can change. Now that's what we need.

Rachel Andrew's photo

The problem is that you don't have a table any more. Semantic table markup is important, when you have tabular data, as it describes the meaning of that content. Now you just have a string of meaningless data wrapped in div elements.

I like the idea though and responsive tables as something of an unsolved problem, I wonder if it would be possible to do something similar with semantic markup. It might require display: contents (which is currently only supported in Firefox).

Show +1 replies
Michael Richins's photo

The best way to overcome this is to use aria accessible features here. This will provide accessibility options for screen readers or voice-over programs.

Ann Mary's photo

Vasan Subramanian Thanks a lot for your help. You have shared the details of using tables in CSS3 Flexbox. And through this post, I got the details of all types of tables we can use. I think it's a piece of useful information.

Fercho Carcho's photo

If you could make it dinamically would be gold. but I think in this way you need to make many settings. It is good for Inspiration. I would love to make it made with vue

Fercho Carcho's photo

Im trying to implement it if anybody interested.

Thiago Lagden's photo

The stylish solution!!

Instead 5-line, I'd make something like this:

Header 1            item 1
Header 2            item 2
Header 3            item 3
Header 4            item 4
Header 1            item 1
Header 2            item 2
Header 3            item 3
Header 4            item 4
Thomas Williams's photo

I really like this idea. I have started to use flexbox to make 2 column lists rather than the float method. Now I like the idea of this table, and I like the way it compresses, but is it possible to use this method on a scrolling table, where the header stays at the top and the data scrolls. I use this kind of table a lot and at the moment I sometimes use css divs or jQuery hacks to get around the problem.

Vasan Subramanian's photo

Yes, it is possible to do a fixed-header table, and I have done it too. But it does involve jQuery hacks (to find the scroll position) and CSS fixed positioning. And, because the header height varies, it makes it all the more complicated ... no simple straightforward way, I am afraid.

GCat's photo

Please check my comment below.

Daniel Buchner's photo

Why not just apply flexbox CSS styles to <table> and <tr> elements themselves? -->

Vasan Subramanian's photo

Yes, that would work for Plain Wrap. But for the other examples, we need to nest some cells within parent containers to keep them together. I could have indeed used nested tables to achieve this, but I found <div>s simpler and easier to deal with in terms of styles.

GCat's photo

I don't think that will be responsive.

Ro Uso's photo

How does the horizontal scrollbar fit into this flex table when the number of columns becomes very large? Also what about fixed columns and fixed rows and their scrolling?

Vasan Subramanian's photo

The whole idea was to avoid a horizontal scrollbar. If the number of columns is too large, I prefer showing them as multiple lines per row rather than let the table overflow the screen horizontally.

Vasan Subramanian's photo

About the fixed header rows when scrolling: please see @gregcatalano's comments. If the header row is below some other section, then things do get complicated, you'll have to trap the scroll event. How that's done will depend on whether you're using jQuery or Angular or something else. I managed to get it done in my Angular.js project: I had to bind to the window's scroll event, keep calculating the offset from top, when it reaches 0, add a class to the header to make it fixed. The code is not clean enough to share it here, apologies.

jj's photo

too bad you have to hard code field widths instead of letting them be resized to their content.

Clem's photo

This is nice, but I tried to create a colspan and I failed. Is there any way to get it working? Otherwise I will have to use table elements.

Liron Burrack's photo

In your experience, are there any browser quirks using flexbox ? (Ie11, Microsoft edge, Safari, Firefox)

Vasan Subramanian's photo

The complete browser compatibility can be found at this page:

With regards to quirks, you should use the Pleeease Play tool to generate browser-specific prefixes for it to work.

Timothy Shaw's photo

Developers and testers usually test website responsiveness using Chrome or safari. Hence these two browsers are very common among people even our core testing team also tests on these browsers.

Timothy, QA Analyst @ Hul Hub

Rian Rietveld's photo

Hey Vasan,

Looks very good :-).

I have one problem with this.

By dismissing the table element you are removing all semantic meaning from the code. All elements are places in a div, creating a flat meaningless DOM. The purpose of the table element is to give meaning to the HTML. Screen reader and other assistive technology and search engines know how to read it and understand it.

By flatting it in divs it becomes unreadable by everyone but signed users.

Kind regards, Rian Rietveld

Bráulio Bhavamitra's photo

please fix images!

Vasan Subramanian's photo

Really sorry ... this is a very old post, and I don't have the images with me any longer. I think they may have been lost in one of the platform upgrades. Syed Fazle Rahman, any clue?

Bráulio Bhavamitra, in the meanwhile, you could use the Codepens mentioned in the article. they have the actual running example.

Syed Fazle Rahman's photo

Vasan Subramanian Bráulio Bhavamitra The images have been fixed now. We were transferring images from Cloudinary CDN to Hashnode's native CDN.