Bring on the tables

Something that often seems to confuse people that are new to CSS-based layouts is the use of tables. I’ve seen plenty of cases where people interpret “avoid using tables for layout” as “don’t use tables at all”. It’s important to remember that tables are still perfectly fine to use – if used correctly.

Yes, do your best to avoid using tables for layout, but for tabular data, tables are what you should use. I’d like to talk about how tables should be used when marking up tabular data. There’s a lot more to tables in HTML and XHTML than just rows and cells. Much more. Especially if you want to make them accessible.

First a bit of background info. The “avoid using tables for layout” blurb can be found in Introduction to tables in the HTML 4.01 Specification:

Tables should not be used purely as a means to layout document content as this may present problems when rendering to non-visual media. Additionally, when used with graphics, these tables may force users to scroll horizontally to view a table designed on a system with a larger display. To minimize these problems, authors should use style sheets to control layout rather than tables.

I’d say that makes it pretty clear, although the word used is should, not must, so there is some flexibility in the specification.

But this article is not about using tables for layout or not. It’s about using tables for their original purpose: marking up tabular data.

When tables are used to mark up actual data, they aren’t just a layout grid. Sighted people can get a feel for the relationship between header and data cells by looking at the layout and visual presentation of the table. Blind or severly vision impaired people can’t do that. For a table to be accessible to people using a screen reader or some other non-visual user agent, it needs to tell the user agent how the information it contains is related.

Fortunately, HTML provides plenty of elements and attributes for that. Less fortunate is the fact that it can be pretty difficult to understand how to use some of these accessibility features. In this article, I’ll try to explain how most of them can be used.

Table headers, <th>

Let’s start with a very simple table that only has a single row of headers, each defining the data in a column. Marked up the old-fashioned way, with just table rows and cells, the markup would be this:

  1. <table>
  2. <tr>
  3. <td>Company</td>
  4. <td>Employees</td>
  5. <td>Founded</td>
  6. </tr>
  7. <tr>
  8. <td>ACME Inc</td>
  9. <td>1000</td>
  10. <td>1947</td>
  11. </tr>
  12. <tr>
  13. <td>XYZ Corp</td>
  14. <td>2000</td>
  15. <td>1973</td>
  16. </tr>
  17. </table>

With no borders or styling, the table will look like this in most browsers:

Company Employees Founded
ACME Inc 1000 1947
XYZ Corp 2000 1973

By styling the table with a bit of CSS, you can make the headers more obvious for those using a graphical browser:

Company Employees Founded
ACME Inc 1000 1947
XYZ Corp 2000 1973

For a sighted person, it’s now quick and easy to make the connection between headers and the data cells they describe. Someone using a screen reader, on the other hand, would hear something like Company Employees Founded ACME Inc 1000 1947 XYZ Corp 2000 1073. Not very easy to make any sense out of.

The first – and easiest – step towards making this table more accessible is to mark up the headers properly. It’s very simple: just use the <th> (table header) element instead of <td> (table data) for the header cells:

  1. <table>
  2. <tr>
  3. <th>Company</th>
  4. <th>Employees</th>
  5. <th>Founded</th>
  6. </tr>
  7. <tr>
  8. <td>ACME Inc</td>
  9. <td>1000</td>
  10. <td>1947</td>
  11. </tr>
  12. <tr>
  13. <td>XYZ Corp</td>
  14. <td>2000</td>
  15. <td>1973</td>
  16. </tr>
  17. </table>
Company Employees Founded
ACME Inc 1000 1947
XYZ Corp 2000 1973

For this simple table, that is enough information for a screen reader to be able to let the user know which header each data cell is related to. A screen reader might say Company: ACME Inc. Employees: 1000. Founded: 1947., and so on for each row. Much better.

Table captions: <caption>

The <caption> element can be used to provide a short description of a table, much like an image caption. By default, most visual browsers render the <caption> element centered above the table. The CSS property caption-side can be used to change that, if necessary. Most browsers will only display the caption either above (top) or below (bottom) the table contents, while some will accept left or right as values. I’ll leave it to you to experiment with this.

When used, the <caption> element must be the very first thing after the opening <table> tag:

  1. <table>
  2. <caption>Table 1: Company data</caption>
  3. <tr>
  4. <th>Company</th>
  5. <th>Employees</th>
  6. <th>Founded</th>
  7. </tr>
  8. <tr>
  9. <td>ACME Inc</td>
  10. <td>1000</td>
  11. <td>1947</td>
  12. </tr>
  13. <tr>
  14. <td>XYZ Corp</td>
  15. <td>2000</td>
  16. <td>1973</td>
  17. </tr>
  18. </table>
Table 1: Company data
Company Employees Founded
ACME Inc 1000 1947
XYZ Corp 2000 1973

You can of course use CSS to style the caption if you wish. However, be aware that it can be a little tricky to style it consistently across browsers. I’ll leave that as another exercise for you.

Explaining the table: the summary attribute

A sighted person can easily decide whether or not to study a table in detail. A quick glance will tell how large the table is and roughly what it contains. A person using a screen reader can’t do that unless we add a summary attribute to the table element. This way you can provide a more detailed description of the table than is suitable for the <caption> element.

The contents of the summary attribute will not be rendered by visual browsers, so make the description long enough for anyone hearing it to understand what the table is about. Don’t overdo it though, and use the summary attribute only when necessary, i.e. for more complex tables where a summary will make it easier for someone using a screen reader to understand the contents of the table.

  1. <table summary="The number of employees and the foundation year of some imaginary companies.">
  2. <caption>Table 1: Company data</caption>
  3. <tr>
  4. <th>Company</th>
  5. <th>Employees</th>
  6. <th>Founded</th>
  7. </tr>
  8. <tr>
  9. <td>ACME Inc</td>
  10. <td>1000</td>
  11. <td>1947</td>
  12. </tr>
  13. <tr>
  14. <td>XYZ Corp</td>
  15. <td>2000</td>
  16. <td>1973</td>
  17. </tr>
  18. </table>

Shortening the headers: the abbr attribute

When a screen reader encounters a table, it can announce the associated header (or headers) before each data cell. If you have long headers, hearing them repeated over and over can get tedious. By using the abbr attribute to provide an abbreviated version of any long headers, you give screen readers something that they can use instead of the text in the header itself. Using the abbr attribute is optional, and most of the time your headers will (and probably should) be pretty short anyway.

If the example table is modified slightly, to make the headers longer, the abbr attribute could be used like this:

  1. <table summary="The number of employees and the foundation year of some imaginary companies.">
  2. <caption>Table 1: Company data</caption>
  3. <tr>
  4. <th abbr="Company">Company Name</th>
  5. <th abbr="Employees">Number of Employees</th>
  6. <th abbr="Founded">Foundation Year</th>
  7. </tr>
  8. <tr>
  9. <td>ACME Inc</td>
  10. <td>1000</td>
  11. <td>1947</td>
  12. </tr>
  13. <tr>
  14. <td>XYZ Corp</td>
  15. <td>2000</td>
  16. <td>1973</td>
  17. </tr>
  18. </table>
Table 1: Company data
Company Name Number of Employees Foundation Year
ACME Inc 1000 1947
XYZ Corp 2000 1973

A screen reader could then read the full length headers for the first row of data, and then use the abbreviation for the remaining rows.

Considering how hard it can be to make data tables fit a layout, I’d say it’s more common to have a need for the opposite: to make the headers as short as possible, or even abbreviated, and use the title attribute or the <abbr> element to provide a longer explanation.

Linking headers to data: the scope, id and headers attributes

Many tables are more complex than the example table I’ve been using so far. I’ll make it a little more complex by removing the “Company” header and changing the data cells in the first column into header cells:

  1. <table summary="The number of employees and the foundation year of some imaginary companies.">
  2. <caption>Table 1: Company data</caption>
  3. <tr>
  4. <td></td>
  5. <th>Employees</th>
  6. <th>Founded</th>
  7. </tr>
  8. <tr>
  9. <th>ACME Inc</th>
  10. <td>1000</td>
  11. <td>1947</td>
  12. </tr>
  13. <tr>
  14. <th>XYZ Corp</th>
  15. <td>2000</td>
  16. <td>1973</td>
  17. </tr>
  18. </table>
Table 1: Company data
  Employees Founded
ACME Inc 1000 1947
XYZ Corp 2000 1973

In this table, each data cell has two headers. The simplest method, markup-wise, of making sure that a non-visual browser can make sense of this table is to add a scope attribute to all header cells:

  1. <table summary="The number of employees and the foundation year of some imaginary companies.">
  2. <caption>Table 1: Company data</caption>
  3. <tr>
  4. <td></td>
  5. <th scope="col">Employees</th>
  6. <th scope="col">Founded</th>
  7. </tr>
  8. <tr>
  9. <th scope="row">ACME Inc</th>
  10. <td>1000</td>
  11. <td>1947</td>
  12. </tr>
  13. <tr>
  14. <th scope="row">XYZ Corp</th>
  15. <td>2000</td>
  16. <td>1973</td>
  17. </tr>
  18. </table>

The scope attribute defines whether a header cell provides header information for a column or a row:

  • col: header information for the column it is in
  • row: header information for the row it is in

Adding a scope attribute with the value col to the headers in the first row declares that they are headers for the data cells below them. Likewise, giving the headers that begin each row a scope with the value row makes them headers for the data cells to their right.

The scope attribute can take two more values:

  • colgroup: header information for the rest of the column group that contains it
  • rowgroup: header information for the rest of the row group that contains it

A column group is defined by the <colgroup> element. Row groups are defined by the <thead>, <tfoot> and <tbody> elements. I’ll get back to those in a bit.

What if you want to keep the “Company” header, and still have the company names be row headers? That would make the cells containing the company names provide both header and data information. In this case, <td> should be used together with the scope attribute:

  1. <table summary="The number of employees and the foundation year of some imaginary companies.">
  2. <caption>Table 1: Company data</caption>
  3. <tr>
  4. <th scope="col">Company</th>
  5. <th scope="col">Employees</th>
  6. <th scope="col">Founded</th>
  7. </tr>
  8. <tr>
  9. <td scope="row">ACME Inc</td>
  10. <td>1000</td>
  11. <td>1947</td>
  12. </tr>
  13. <tr>
  14. <td scope="row">XYZ Corp</td>
  15. <td>2000</td>
  16. <td>1973</td>
  17. </tr>
  18. </table>

This way, visual browsers won’t display the company names as headers by default, so a bit of CSS is needed to fix that. For this example, I used the following CSS:

  1. td[scope] {
  2. font-weight:bold;
  3. }

Note that this rule uses an attribute selector, which Internet Explorer does not support. A workaround for that would be to add a class to any data cells that should be styled as a header.

Table 1: Company data
Company Employees Founded
ACME Inc 1000 1947
XYZ Corp 2000 1973

Another technique for connecting a table’s data cells with their appropriate header involves giving each header a unique id. A headers attribute is then added to each data cell. This attribute contains a list, separated by spaces, of the id of every header cell that applies to that data cell. This technique is more complicated, and should only be used when there are data cells that need to be linked to more than two header cells, and the scope attribute is insufficient, as in a very complex or irregular table.

To illustrate this, I’ve changed the table to show the number of employees of each sex the companies have:

  1. <table class="extbl" summary="The number of employees and the foundation year of some imaginary companies.">
  2. <caption>Table 1: Company data</caption>
  3. <tr>
  4. <td rowspan="2"></td>
  5. <th id="employees" colspan="2">Employees</th>
  6. <th id="founded" rowspan="2">Founded</th>
  7. </tr>
  8. <tr>
  9. <th id="men">Men</th>
  10. <th id="women">Women</th>
  11. </tr>
  12. <tr>
  13. <th id="acme">ACME Inc</th>
  14. <td headers="acme employees men">700</td>
  15. <td headers="acme employees women">300</td>
  16. <td headers="acme founded">1947</td>
  17. </tr>
  18. <tr>
  19. <th id="xyz">XYZ Corp</th>
  20. <td headers="xyz employees men">1200</td>
  21. <td headers="xyz employees women">800</td>
  22. <td headers="xyz founded">1973</td>
  23. </tr>
  24. </table>
Table 1: Company data
  Employees Founded
Men Women
ACME Inc 700 300 1947
XYZ Corp 1200 800 1973

As you can tell, this method quickly gets really complicated, so if it is possible, use the scope attribute instead.

Spanning rows and columns

In the old, tables-for-layout days, the attributes rowspan and colspan were often used to make table cells span several rows or columns in order to put all of the neatly sliced images back together. Those attributes are still around – there is no way to use CSS to specify spanning. If you think about it, it’s quite logical: row and column spans are part of a table’s structure, not its presentation.

Columns and column groups: <col> and <colgroup>

HTML provides the <colgroup> and <col> elements for grouping related table columns. This allows (in some browsers) the use of CSS to style columns independently. Column groups can also be used by the scope attribute to specify that a cell contains header information for the rest of the column group that contains it.

That’s all I’m going to say about columns and column groups here. For more detailed information, see the links in the section “What I didn’t tell you”.

Row groups: <thead>, <tfoot>, and <tbody>

Table rows can be grouped into a table head (<thead>), a table foot (<tfoot>), and one or more table body (<tbody>) sections. Each row group must contain one or more table rows.

If a table has a head section, it must appear before the table foot and body sections. A table foot section must appear before the body section(s). If no head or foot section is used, the <tbody> element is not required (but not forbidden either, so add it if you like). The structure of a table that has row groups looks like this:

  1. <table>
  2. <thead>
  3. <tr></tr>
  4. … more rows for the table head
  5. </thead>
  6. <tfoot>
  7. <tr></tr>
  8. … more rows for the table foot
  9. </tfoot>
  10. <tbody>
  11. <tr></tr>
  12. … more rows for the first table body
  13. </tbody>
  14. <tbody>
  15. <tr></tr>
  16. … more rows for the second table body
  17. </tbody>
  18. … more table bodies if necessary
  19. </table>

Row grouping can be useful for several reasons:

  • It makes it easy to style the head, foot, and body sections of a table independently of each other, without having to add classes to any elements.
  • When printing long tables, some browsers (like those based on Mozilla) will repeat the information in the head and foot sections on every printed page, making it easier to read the printed table.
  • Separating the head and foot from the body also makes it possible for browsers to support scrolling of the table body only.

For data tables only

Everything described here is related to the use of HTML tables to structure and present data. If you use tables for layout, neither of the techniques described here should be used. No summary attribute, no headers, no <caption>, nothing. Just a plain, old-fashioned layout table, consisting of no other elements than <table>, <tr>, and <td>. Otherwise you will risk confusing users of non-visual user agents even more.

The benefits

It may look like a lot of work to create accessible data tables in HTML. For complex tables, it is. Sometimes to the point where it gets almost impossible to do by hand. For simple tables though, using header cells with a scope attribute is quick and easy.

It’s obvious that people using screen readers or other assistive technology benefit from tables that use the available accessibility features. Trying to make sense of a large and complex table by listening to it can still be very difficult, so if at all possible, simplify the table.

Less obvious is that designers and users of graphical browsers also benefit: an accessible table has plenty of structural hooks to apply CSS to, and good styling can make the table more usable for everybody.

What I didn’t tell you

There is even more to data tables than I have mentioned here. For example, I haven’t mentioned the axis attribute at all (until now), and I did not describe the <colgroup> and <col> elements in great depth. Neither have I gone into formatting and styling or the border models. Also missing is an example of a really complex table.

For those of you looking for even more detailed information, here are links to some further reading:

Translations

This article has been translated into the following languages:

Posted on October 27, 2004 in (X)HTML, Accessibility, Web Standards

Comments

  1. Great post. Definitely going to bookmark this one! Keep up the good work.

  2. Amazing work. The best writing on the subject I’ve ever seen. Thanks for sharing.

  3. Many thanks for this very good and useful article plus the complementary links.

  4. I thing have struck me with tables. What is the purpose of having both summary and caption. Many times I notice that I put the same thing in the two. So if just using one, which one is to prefer?

    Another thing I have a mental problem with is when to put things in tables. Should it just be numbers or is it ok with text. For example,

    <table> <tr> <th>Details</th> <th>Information</th> </tr> <tr> <td>A long brown bear with hungry eyes</td> <td>Brown bear</td> </tr> </table>

    Is that ok? But then, should the text be in a p?

    <table> <tr> <th>Details</th> <th>Information</th> </tr> <tr> <td><p>A long brown bear with hungry eyes</p></td> <td><p>Brown bear</p></td> </tr> </table>

    Thanks for the post

  5. What is the purpose of having both summary and caption.

    That’s quite simple - Caption is just a title of a table (for both sighted and blind readers), while summary attribute is long(er) description of table data, purpose, layout and such (primary for blind readers).

  6. Should it just be numbers

    Of course not! Any tabular data

    should the text be in a p?

    You don’t have to include <p> inside <td>, but I guess, you can do that when you want to include more than one paragraph in a single table cell. But do you really want to?

    BTW - This is just the same situation with <li> tag…

  7. hmmm… it was ok on preview but now it’s broken :-(

    again: You don’t have to include p inside td […] same situation with li tag…

  8. October 27, 2004 by Grant Gatchel

    Enlightening work; very well done.

    I was never aware of these extra tags and attributes to tables to help organize and describe information. This does bring up an idea I’ve been meaning to do for a while though: download a screen reader.

    I apologize for being somewhat naïve and not googling this first, but does anyone quickly know of a good browser compatibility chart for these table tags and attributes?

  9. Grant Gatchel: I would say that they all work great in all browsers. I have not found one that doesn´t support them. Even Lynx works well with them.

  10. Me again :)

    I must say the way you made the code examples was cool way of using ol. Mayby not semanticly correct but anyway. Too bad it is not valid to do:

    <code> <ol> <li>test</li> <li>test</li> </ol> </code>

    Sorry for be off topic

  11. Whoa, great article, I didn’t know there was so much about tables.

  12. October 27, 2004 by Roger Johansson (Author comment)

    Jens: I think it’s pretty semantic, in that it adds line numbers even if you view the document unstyled. But you’re right: every line should be wrapped in a <code> element. I’ll fix that as soon as my ‘net connetion at home starts working again.

    Anyway, I didn’t come up with the line numbering idea: it’s something I “borrowed” from Dunstan Orchard, who got the idea from Simon Willison.

  13. October 27, 2004 by Erwin Heiser

    Great article. I’m currently reading the excellent book on accesibility by Joe Clark and this summarises a lot of the stuff that makes tables more accesible. Great bunch of links too. Keep up the good work!

  14. October 27, 2004 by Erwin Heiser

    Great article. I’m currently reading the excellent book on accesibility by Joe Clark and this summarises a lot of the stuff that makes tables more accesible. Great bunch of links too. Keep up the good work!

  15. One more link to consider: Dive into Accessibility - among many other things this book includes “real life” examples of importance of “extra tags” in tables.

  16. Excellent.

    Thank you for this cracking article, It’s just what I’ve been looking for.

    Cheers!

  17. I had been trying to explain to people I work with for a while now that tables should be used for tabular data rather than layout. Thank you for this article. Hopefully some other people at my job will read this.

  18. Long live tables for tabular data! “I like ‘em so much, I put one on me ‘omepage”

    Thanks for writting this out Roger :) It’ll be good to have something to point to when the next person asks how tables should be used.

  19. October 29, 2004 by Trent

    Excellent article. I was not aware of the “caption” element.

  20. Great work.

    Not seeing this article, I whould forget about table tags.

  21. Great article. There was a heap there I hadn’t seen before, especially the “scope” attribute.

  22. October 30, 2004 by Luke Shingles

    I couldn’t believe there were so many attributes I’d never seen before - scope, headers and abbr were all new to me. Time for me to read the XHTML Modularisation doc again.

  23. Yes, an excellent post. (I’ve linked your site from mine.) I think it’s important for people to understand the logical reason behind usage of certain elements of HTML, including tables. Thanks to CSS, we can now use tables for what they were originally intended for.

  24. Great post! However:

    When a screen reader encounters a table, it is common for it to announce the associated header (or headers) before each data cell.

    The screen readers I have tried do not do this (at least not with default settings). Usually the listener has to press a key combination to hear the header cells again.

    I have started writing on a similar topic: Grouping table data (work in progress)

  25. November 2, 2004 by Roger Johansson (Author comment)

    Peter: I’d say that what’s most important is that the headers can be announced if the user wants to hear them. I’ll rephrase the sentence you quoted to reflect that.

  26. November 2, 2004 by Tech Notes

    Great article. There were some tags I’ve used infrequently (without fully understanding them) and some I wasn’t aware of.

    I’ll be forwarding this to a number of colleagues.

    BTW: all your nice formatting breaks in the print version, when I tried it with Opera and Mozilla. :-(

  27. November 2, 2004 by Roger Johansson (Author comment)

    Tech Notes: That’s the whole point of the print version :) It removes everything but the main content and basically just leaves the text.

  28. IE doesn’t use the THEAD and TFOOT tags properly by default when printing (ie: repeating those sections on every page for really long tables when printing). You can fix this through css like this:

    thead { display: table-header-group; }
    tfoot { display: table-footer-group; }
    
  29. November 17, 2004 by Simon Farine

    Hello, this is juste my place where i keep my notes. It’s just for me you know. Only for me. Usually, my place is password protected. Sorry for this bad felling. Sorrrrrrry Great article!

    “Author : Roger Johansson Hi. Nice article. Reminds me a lot of Bring on the tables over at my site. Hrm.”

  30. November 17, 2004 by Simon Farine

    And I like the same music as you (Dj Krush, Esbjörn Svensson Trio,…). (I’m a record dealer)

  31. November 17, 2004 by Roger Johansson (Author comment)

    Simon: Apology accepted, and no hard feelings :-)

  32. November 19, 2004 by Chris Shelverton

    Have been in web dev. for a long while now. Is possible one of the best articles about tables I have seen. Well done. By the way I hate tables ‘cause 90% of people dont know when and how to use them.

  33. Great article, and a big help. Know anywhere I can find out how to style a column of data with CSS?

  34. November 21, 2004 by Roger Johansson (Author comment)

    Matt: I haven’t done any extensive research on column styling, but the specs state that you can only apply four CSS properties to col and colgroup elements: border, background, width, and visibility. IE/Win lets you apply other properties than those, but it shouldn’t.

    Ian Hixon has written a bit about the issue: The mystery of why only four properties apply to table columns.

  35. Id say that whats most important is that the headers can be announced if the user wants to hear them.

    Please note the speak-header property:

    This property specifies whether table headers are spoken before every cell, or only before a cell when that cell is associated with a different header than the previous cell.

    (Just ran into this while reading the specs, so can’t tell you about support or its working)

  36. Btw, in the CSS 2.1 spec, the speak-header property can be found in Appendix A - Aural style sheets

  37. February 12, 2005 by david currey

    Anyone know the logic behind the tfoot having to appear before any tbodies in the source html?

  38. February 12, 2005 by david currey

    I found the answer moments after asking my question from the html401 tables spec

    TFOOT must appear before TBODY within a TABLE definition so that user agents can render the foot before receiving all of the (potentially numerous) rows of data.

  39. February 22, 2005 by Thomas

    You say that TD should be used together with the scope attribute if the cells containing the company names provide both header and data information. Would it be horribly wrong to use TH there as well? I just felt like you could have elaborated a little there…

    Oh by the way, I had to enter my name and email twice because I clicked the radio buttons. Kind of annoying… I thought “Remember the above info” was some sort of acceptance of usage terms or something, but know I get it… :-)

    Thanks for a great site!

  40. I was actually looking for examples of accessible and stylish tables and came across this article on my travels. It’s a great page to send people to with regards to getting people off tables for layouts and how to use them for their intended purpose.

    A table potentially alters, albeit temporarily and if done incorrectly such as using for layouts, document structure, so it’s important to use them wisely with regards to captions, summaries, headers, rows and footers.

    A page to bookmark!

  41. I particularly liked this article. Though you didn’t mention it, your listed links (after) did: you can easily put the caption below the table with CSS. Just define:

    caption { caption-side: bottom; }

    http://www.w3.org/TR/CSS21/tables.html#q6

    (with glass raised): TO THE TABLES!!!

  42. Great article. I’ve been looking for it

  43. Very interesting and helpful! Especially you also described how visually impaired people will perceive the output. I just attended a short presentation by a blind person, and he told us about the same stuff, just not the programming details that this might imply! More of this!

  44. Excellent work. I’ve used infrequently.

  45. Great Article!

  46. June 28, 2005 by craig

    Is there any way I can make the heading fixed on the page? This is useful with long tables.

  47. June 29, 2005 by Roger Johansson (Author comment)
  48. I was wondering what to do when you have some * in your table that refers to a footnote that has to be placed under the table.

    Is it ok placing some (p)* footnote txt(/p) under the table?

    (table)
        (tr)
            (td)Company(/td)
            (td)Employees(/td)
            (td)Founded(/td)
        (/tr)
        (tr)
            (td)ABC Inc*(/td)
            (td)1000(/td)
            (td)1947(/td)
        (/tr)
        (tr)
            (td)XYZ Corp(/td)
            (td)2000(/td)
            (td)1973(/td)
        (/tr)
    (/table)
    (p)ABC Inc* is part of A-Z Group(/p)
    
  49. Nice article. Im searching nice ways to present huge data tables. So the link in post #47 helped me alot. But I found another nice solution. It’s with fixed header and fixed first column - http://aktuell.de.selfhtml.org/artikel/javascript/scrolltabelle/index.htm

    I tried todo it with pure CSS and without JavaScript. But i didnt found the solution yet.

  50. Great article. That’s the best piece of writing I have seen regarding HTML tables. I have learned more from your article than reading any of the HTML tutorials available online. Recently, I started learning more about website design, usability and accessibility. Your effort has given me aspirations to be a better coder and writer.

  51. A truly well written article. Well done.

  52. Thanks for not being the “No tables at all” type.. I’m thinking hard about how to really making some skinnable (fully css) sites/applications where tables can live too using the width 100% “trick”.. last time I tried absolute positioned divs with tables inside, the “width 100%” screwed it completely up… sigh.

  53. Great article, just been doing some complex design work for a design agency and the info in this article gave me some great ideas on how to make the code short and simple!

    thanks

  54. Nice. This is visible in all the brousers??

  55. November 29, 2005 by joseph

    EXELLENT pure EXELLENCE

  56. A good post. Yeah, it’s funny at times when people go crazy just to get they’r code so tables when just what they need was tables.

  57. Not sure if anyone mentioned this but I would NEVER embed a p inside a td.

    The main reason is that to maximise accessibility you should be using scalable font sizes (to allow font to resize in IE) and you should NEVER embed elements with scalable font values inside other elements with scalable font values i.e. an element with a value of 90% inside an element with a value of 50% could have a final display value of 45% (depending on the browser). I am sure you have all seen examples of this where fonts in tables are so small they are unreadable.

    The other big reason is that tables are for tabular data and p’s are for paragraphs and we should always use XHTML elements as they we initially intended to be used. IMHO this is a key part of good coding practice.

  58. I had no idea about scope. Simply awesome! Thanks.

  59. Great read, very informative, bookmarked on del.icio.us!

  60. Carl, you’re looking at the wrong thing. The problem doesn’t lie in putting p elements within td elements; the problem lies in having something stupid like font-size: 50% in a stylesheet without knowing how it would interact with a page. There’s nothing inherently wrong with combining relative font sizes, and the rules are quite clear in how they are applied.

    As for your other reason, well sorry, but sometimes what you are marking up is logically a paragraph within a table, so a p element within a td element is exactly what should be used.

  61. Great article. One of the best I’ve seen on tables, I think. Very thorough, and bookmarked for my own reference in future. :D

  62. January 30, 2006 by Shelley

    Loved the article. However how do you code so that the blind reader actually picks up the table headers - or how do you adjust the blind reader to read correctly so that table cells are grouped?

  63. Great article, the best I could find describing how to use tables.

Comments are disabled for this post (read why), but if you have spotted an error or have additional info that you think should be in this post, feel free to contact me.