How to Create Responsive Tables in WordPress

Use WordPress? Do you have tables in your posts?

These can be tricky to edit as well as display properly on a mobile display.

I’ve already rounded up a bunch of possible solutions, but here I’m going to break it down further, and outline what I’ve been doing.

1. Adding and Editing Tables

If really want to understand HTML tables, read Chris Coyier’s comprehensive guide.

It is possible to add and edit a table in WordPress in the visual editor. To do this you need to activate the table button in the toolbar.

Do this by adding a plugin called MCE Table Buttons.

On the visual editor, make sure your click the rightmost icon (the toolbar toggle shows the enhanced toolbar).

toolbartoggle

Now the toolbar shows a second line – including a new TABLE button.

enhancedtoolbar

This button has a dropdown menu with a number of options for creating a table.

  1. Insert the table according to the number of rows and columns you need.
  2. Click in the first row. Then drill down the table button: Row / Table Row Properties. Set the Row Type to header.
  3. Select the first row. Using the table button: Cell / Table Cell Properties. Set the Cell Type to Header cell.

Don’t drag the table to resize it. This will add in fixed widths which will not go well on a responsive site.

Advertisement

This will give us a semantically correct table. The source looks like this:

<table>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>

Formatting the Table

All formatting should be done with CSS. Your table should not contain widths in the HTML or other formatting markup.

Most themes will have their default table styles. From here you can either edit the theme CSS. Or, add your extra table CSS into the Custom CSS box on your theme options (most commercial themes have this).

Beverage Short caffeine Tall caffeine Grande caffeine Venti caffeine
Brewed Coffee 180mg 260mg 330mg 415mg
Brewed Decaf Coffee 15mg 20mg 25mg 30mg
Caffè Americano 75mg 150mg 225mg 300mg
Caffè Latte 75mg 75mg 150mg 150mg

Some of the more common formatting you might want:

Striped Rows
tbody tr:nth-of-type(2n) {background-color: #f0f0f0;}

Nice Heading Row
th {background-color:#018DB1;font-weight:bold;color:#fff;}

Bolded First Column
tbody tr td:nth-of-type(1) {font-weight: bold;}

Formatting for Mobile Layouts

Set a media breakpoint in your CSS according to your design. In this example any layouts narrower than 600px will get the mobile optimized table.

You can resize your browser to see this in action. I’ve pasted a screen capture to show you.

resptable


@media screen and (max-width: 600px) {
table {width:100%;}
thead {display: none;}
tr:nth-of-type(2n) {background-color: inherit;}
tr td:first-child {background: #f0f0f0; font-weight:bold;font-size:1.3em;}
tbody td {display: block;  text-align:center;}
tbody td:before { 
    content: attr(data-th); 
    display: block;
    text-align:center;  
  }
}

Getting Column Headings to Appear in Each Cell

Props to Dudley Story. This code has been adapted from that example.

We need to go through each table and extract out heading text. Then concatenate this into each cell.

jQuery is not required. This code must be placed before the </body> tag, but make sure it is after the content of your page. Many themes also have this as an option. If you don’t have table headers (are not using thead) the code will still work.

<script>
(function () {
	var headertext = [];
	var headers = document.querySelectorAll("thead");
	var tablebody = document.querySelectorAll("tbody");
	
	for(var i = 0; i < headers.length; i++) {
		headertext[i]=[];
		for (var j = 0, headrow; headrow = headers[i].rows[0].cells[j]; j++) {
		  var current = headrow;
		  headertext[i].push(current.textContent.replace(/\r?\n|\r/,""));
		  }
	} 
	
	if (headers.length > 0) {
		for (var h = 0, tbody; tbody = tablebody[h]; h++) {
			for (var i = 0, row; row = tbody.rows[i]; i++) {
			  for (var j = 0, col; col = row.cells[j]; j++) {
			    col.setAttribute("data-th", headertext[h][j]);
			  } 
			}
		}
	}
} ());
</script>

That’s about it.

You don’t have to use large jquery plugins.

Hi, I'm James, and for the last decade I've made a living by making my own blogs and websites.
Updated: January 8, 2017

108 Comments

  1. Dear James, When there is more than 2 table then header of below one is overlapping on another. Please have a look. What is wrong and what is solution. your help is appreciated.

    • Sandeep can you paste in an example URL to look at?

      • Hello James, Can you provide email ID to review code? Here is link http://staging.amvicsystem.com/resources/amvic-quick-estimator/

        Problem has 2 input table and 2 out put table. You can look that on minimizing, Height, Length, thickness if table is overridden by Width(Shortest Dimension(ft)), Length(Longest Dimension(ft)) and Concrete Topping(in) of second table.

  2. Beautiful!! Thanks so much. Been trying to figure out a solution to this for a while. Happy it’s plugin free too! 🙂

  3. I wish WordPress added a very good tables inbuild in the next release. It should be basic feature. Thanks for your code. I hope it works for me.

    • You’d have to completely customize the javascript to concatenate the first and second header rows together.

      • Ok, thanks, I’ll pass that on to my Js dev.

        Appreciated 🙂

          • Tabular data on mobile is difficult – by nature tables are for large displays. I think it’s fine what you’ve got. One thing I would like to work on is an ‘accordion’ style table where you can show/hide rows.

      • My dev says he has to use jquery to make the customization work. Does that sound right to you?

        • jQuery certainly makes things easier — but seems a shame to have to load the jQuery library just for one purpose.

          • Tell me about it!

  4. I use a lot of tables on my site and this is great, any chance of making the table an accordion so all you see is the head of the table until you click it and then the body displays underneath?
    Thanks

    • Good idea, although the biggest challenge is indicating to the user that they can tap to display more.

  5. Hi Kevin,
    Thanks for sharing this code. I’m trying to make mobile-friendly a simple 3 X 2 table, without headings. So I’m ok with each cell appearing in new row in mobile version. But it never works with this code.
    Please, let me know what should I modify here.

    Thank you

    • Kate, I’ve finally updated the code to fix a Javascript error that happened if you didn’t have thead in your table. If your having problems still, let me know your URL and I can take a look.

  6. Thanks for Your article … it work nice

    by the why your theme so beautiful

  7. headertext[h] is undefined

  8. The code doesn’t works for explorer edge

  9. Not sure why but it is stripping out my TH data? Css is correct and js is executing?

  10. Hi. Great script. I can only get it the mobile column headers to work on the first table on a page… Should it work for all tables on the page?

    • Yes, all tables on the page. Check that each table has both a thead and tbody.

  11. I have more than one table on my page and only want headers on one of the tables. Can you show me how to limit the script to a certain table ID or something like that to control it?

    • You can add an ID to your table:

      <table id=”customers”>

      In the CSS you’ll need to create an extra rule:

      #customers tbody td:before {
      color: #444;
      }

      Because it’s an ID it will override the other color rule.

      • Hello James, I do not know JS. Do I need to add the table name to the script somewhere to limit headers only added to the named table:

        var headertext = [];
        var headers = document.querySelectorAll(“thead”);
        var tablebody = document.querySelectorAll(“tbody”);

        for (var i = 0; i < headers.length; i++) {
        headertext[i]=[];
        for (var j = 0, headrow; headrow = headers[i].rows[0].cells[j]; j++) {
        var current = headrow;
        headertext[i].push(current.textContent);
        }
        }

        for (var h = 0, tbody; tbody = tablebody[h]; h++) {
        for (var i = 0, row; row = tbody.rows[i]; i++) {
        for (var j = 0, col; col = row.cells[j]; j++) {
        col.setAttribute("data-th", headertext[h][j]);
        }
        }
        }

        • The code is designed to efficiently grab every table on the page.

          You could do something like this.

          var headers = document.querySelectorAll(“thead.domobile”);
          var tablebody = document.querySelectorAll(“tbody.domobile”);

          Then in your HTML add class to both the thead and tbody element of the table you want to render in mobile:

          <thead class=”domobile”>

          <tbody class=”domobile”>

          This is just off the top of my hide. Not sure if it works.

    • Change this CSS, and put in your decided color. This will only color the prepended heading text.

      tbody td:before {
      content: attr(data-th);
      display: block;
      text-align:center;
      color: blue;
      }

      • I will try it. Thank you.

      • Works great! Thank you.

  12. Small correction:
    For the “Nice Heading Row” the code reads
    th {background-color:#018DB1;font-weight:bold;color:#fff;}

    It should say “thead” instead of “th”

    Thanks for sharing, it’s helped me style my tables way better!

    • Sorry, nevermind! I was using this on a table in WordPress which had a tag but didn’t have tags in it, so that’s why it wasn’t working!

      Just wondering though, is it not better to style the entire rather than the individual heading items ()?

      Thanks again!

  13. There is a conflict with the JS.
    common.js:884 Uncaught TypeError: Cannot read property ‘0’ of undefined(…)

    It shows the error at this line below;
    col.setAttribute(“data-th”, headertext[h][j]);

    Why would it be giving me this error?

    • It means you are missing a thead and/or th in your tables. I need to fix the code to better account for this. The tables need to have a heading line so the code can figure out what to put in each cell.

        • You are missing thead in your table markup. The first row should be inside a thead tag. See the example table markup above.

  14. Have you included the example Javascript in your site?

  15. Hey,
    thanks for this blog entry! I’ve been looking for something like this everywhere. It worked pretty well, however, I can’t seem to figure out how to make the second row in the mobile version. I guess I have to customize the provided css code but I can’t seem to get it right.
    Is it even possible to only hide an entire row in the mobile version?
    Thank you!
    Nadja

  16. For those of you who aren’t coders or css savvy, I found an easy to use WP plugin. “Responsive Scrolling Tables detects when tables are bigger then their containers and makes them scroll instead of flowing over the boundary of the container.”

    You can find it in WP plugin directory – Responsive Scrolling Tables

  17. Thank you, but thank you very much! You rock! I have found at least what I am looking for long time…
    Thank you for your time writing this article about responsive table.

    Best,
    Andreas

  18. Oh and did I mention that the plugin is mobile responsive too? You can set just how much space the table will consume, no matter the size of the screen!

  19. Thanks for sharing this. Do you know if it is possible to stylize the data-th text using css?

    I would like that text to appear as simply bold and black, without altering the style of what’s already in the respective , which in my case is green. Thanks for any suggestions.

    • See the styles for tbody td:before {}

      Just add some more CSS inside there.

  20. Very useful. Thank you so much

  21. Thank u James….

  22. Wonderful article. Could you or someone tell me how do I get this type of table – “http://www.authorityhacker.com/best-chrome-extensions/” under “QUICK NAVIGATION”,

    I need
    *background gray
    *background blue on quick navigation

    Any idea James?

    • Solved by myself. In Genesis theme there is a Script session on a page, but it inserts the code in the html , not after the content.

  23. That’s awesome to see this awesome post. I’m trying to make a responsible table in many ways but your way (with Javascript) bring me to heaven quickly. It saves my day!

  24. Hi
    I am new to WordPress and am trying to insert a table into a web page. I have installed the Easy Table Plugin which led me to believe that this would simply add an icon onto my existing toolbar, allowing me to insert a table? Is this not the case?

    Thank you.
    Louise

    • I took a quick look at the easy table plugin – this uses shortcodes to create tables.

      Shortcodes are something in wordpress where you use square brackets in your post. The plugin then renders these shortcodes into HTML.

      Like [table] would result in WordPress creating all the table HTML.

      In my post here the only plugin I use is one (MCE Table Buttons) that adds an extra button to the formatting toolbar. Perhaps this is what you were intending to use.

  25. Just what I was looking for, many thanks. I am using Tablepress and it all works fine for one little detail, the td-text and theader are left aligned on mobile, like this: http://prntscr.com/a0yh64

    Any ideas?

    • You’ll want to contact the authors of tablepress. However it could be nothing more than checking the text-align styles for the table and td.

  26. Hey,

    awesome script, Thanks a lot!

    It only seems to have a bug when the table heading has two words. When scaled down, it drops the last letter of the first word. Example:

    full width / scaled down: http://imgur.com/a/tDudl

    any Idea what might be causing this?

    • Luca can you copy and paste in the code again. I’ve removed a regular expression that seems to cause some grief for some people. Should work fine now.

  27. Thx man for this! Everything is working as i wish 🙂

  28. I like the idea and the way it looks, but the default Android browser turns it into a mess when you rotate the screen. Each time you rotate it back, it seems to get worse.

    Not sure why. It works fine in Chrome on the same phone, but I’m guessing more people just use the default browser.

  29. Thank you!

  30. Hi

    Tnx alot.

  31. Hi James, belay that request please. I just checked on a Kindle Fire and it looks great. I first tried a phone and the screen is simply too small to cope with all the data. I doubt many, if any on my uses will use a phone to see the site. Thank you once again.

  32. Many thanks for the invaluable reply. That has almost got it right. However, whilst the team name is now where it should be, the remaining titles are still in a line across the top. Any ideas?? Thanks.

  33. Hi James, I am trying to my tables sorted as per your excellent scripts. However, it does not seem to be happening for me. Some of it works but other parts do not.

    One table consists of 8 columns with titles. 10 rows 9 of which are with team position number. the body of the table contains the data.
    The row of titles are not displayed along with the position number and data. It is in a long line across the top. You can see what I mean here: http://www.amigosbowlingleagues.co.uk/friday-standings/

    I have added the code to the Custom Header Code for the theme. I assume that this is correct. Any help greatly appreciated.

    • I took a look, and you will need to get the Javascript at the end of the page. Perhaps the theme has an option for custom footer code? If the Javascript is at the head, then the DOM elements have not yet been rendered for the code to manipulate.

  34. it works, very helpfull..thanks mate…

    • Too many colmtimenps too little space, thanks!

  35. Hey man you are the man!! I searched so long till i found your blog, easy and everybody can do it, thank you so much !!

  36. Thank you so very much for posting this! It was incredibly easy to implement and looks beautiful!
    You rock!

  37. It works great but it doesn’t break longer lines of text, so you still get a horizontal scrollbar on very small screens (smartphones).

    Any idea how to get the text to break into several lines?

    • Could apply word-wrap: break-word; to the TD

  38. Jquery not working, no errors but cannot view the change specified. can you help.

    Need a help ASAP

  39. Getting a wildly different result and can’t for the life of me figure out what I’m missing. Inspecting via Firebug to see if some of my theme CSS is messing up yours, but can’t locate anything. Any ideas? Very much appreciated as your example does EXACTLY what I need — IF I can get it to work!

    http://cre8tives.org/table-test/

    • Doesn’t look like all the CSS and JS has made it to your page (I just had a quick look).

  40. I’ve replaced the line:

    headertext[i].push(current.textContent.replace(/r?n|r/,””)); with

    headertext[i].push(current.textContent);

    And all seems OK now. I’m not sure why it needs to be there but then I’m not so good at regular expressions, so if you can explain that would be great

    • The regular expression removes any CRs (carriage returns) or CRLF (Carriage return line feed) from your markup. Sometimes, say if you are minifying HTML you might end up with some spurious linefeeds in your markup.

      To be honest it probably doesn’t need to be there unless you have this in your code. If it was removing actual letters from your HTML then it must somehow have been messed up during the copy and paste process.

      The n (backslash n) means it’s an escaped character – rather than an actual “n”.

  41. I’ve getting a similar issue to Marcus, in that some letters are removed from the table headers. It seems to be letters ‘r’ and ‘n’ for some reason. I’ve copied and pasted the script exactly as it is here. I can’t provide a url as it’s a private site, but here’s a link to a screenshot that illustrates the issue:

    http://www.awesomescreenshot.com/image/374458/7e264c185b3fc553630c5f7d3b62d7e8

    • Michael, that worked for me. Thanks!

  42. James, this is great & thank you for sharing! I have a question on implementing it. Everything works well on my site, except that the “data-th” field on the mobile version cuts off the last letter of my item.

    It should read “Caliper” & instead just reads “Calipe”. If you have any thoughts/advice on this, it would be much appreciated.

    I can send the URL to the site if you need it…just didn’t want to put that into this comment in case it gets edited out.

    • Are you sure the code is copied exactly? I’m thinking the regular expression when it does the replace could have been messed up. Feel free to post your URL

      • Hi James, I think that was it…an issue with the regular expression replace function. I used Michael’s modified code below & it seems to be working well.

  43. Awesome job, works perfectly and easy for a client to use

    • Robert, try removing out all the ‘data-th’ attributes from your HTML. And… it should all still work.

      The idea of this code and script was so that you did not need to go thru all your markup and add in all the column headers. The javascript will go thru and pull that out for you from your headers.

      Less markup = less time and chance for errors.

  44. Hi I’m Bayanda , I just want to ask which plugin did you use for your
    contact form?

    thank you.

  45. Wouldn’t it be better to actually use pseudo css ::before/::after to get those headers to show up in each cell?

    I’m trying to figure a downside in doing this instead using js but i’m pretty in blank here 😐

  46. Get responsive menu here responsivemultimenu.com

  47. James,
    Thank you for posting this solution. I am trying to adapt this to the Hueman Child theme in WordPress. Can you pass on any pointers for incorporating this solution? I am particularly unsure how to add the script.
    Thank you.

    • Are you talking about adding JS to child themes in general?

      • Thanks, James. I am trying to get your code loaded properly on a page. I can get it to work if I use a plugin that adds the script to the footer, but I wanted to add it without using an additional plugin.
        I am trying to use wp_register_script and wp_enqueue_script as my understanding is that is the preferred way to load javascript.
        Eventually I want to use a shortcode to run wp_enqueue_script, but for now I have it set up as follows in the child theme’s php file:

        /* ————————————————————————- *
        * Custom functions
        /* ————————————————————————- */

        // Add your custom functions here, or overwrite existing ones. Read more how to use:
        // http://codex.wordpress.org/Child_Themes
        function register_my_scripts() {
        wp_register_script ( ‘tablechanger’, plugins_url( ‘/js/tablechanger.js’, __FILE__ ), array(), ‘1.0’, true );
        wp_enqueue_script ( ‘tablechanger’ );
        }

        add_action( ‘wp_enqueue_scripts’, ‘register_my_scripts’ );

        /* add_shortcode ( ‘tablechanger’, ‘tablechanger_handler’ );
        function tablechanger_handler() {
        wp_enqueue_script ( ‘tablechanger’ );
        } */

        The script gets registered, but it doesn’t run.
        Do you have any suggestions?

        • I got it to work. I had to change plugin_url to get_stylesheet_directory_uri

Add a Comment