TABLEs on non-TABLE Browsers
(2nd Ed., 1998)

(with later amendments and comments)


This page was started quite a few years ago, to study a specific problem with HTML tables. It does not attempt to be a balanced tutorial on HTML table design in general, and the issue which it addresses is now of, at best, only specialised interest.

When HTML Tables are viewed on non-table-capable browsers, the result is usually a mess. We investigated ways of marking up tables so that they would offer some reasonable level of fallback capability when viewed on non-table-capable browsers.

The first edition of this page was started at a time when there was still a significant proportion of browsers that had absolutely no support for TABLEs. In mid-1998, this no longer seemed realistic: many of the details and reports of problems with antique browser versions were deleted at that point.

By 2003, Lynx (version 2.8.4rel.1 was reviewed) was already doing quite a decent job with tabular data, without the additional help described in this article. So, unless you need to worry about folks using older versions of Lynx (version 2.8.2rel.1 behaved in the old way), this document can now be considered of only historical interest. According to the Users Guide, this method of dealing with tables was introduced at 2.8.3, and is denoted TRST, "Tabular Representation for Simple Tables". Documentation can be found at the Lynx web site,


There are numerous situations where the "TABLE" construct is ideal for presenting information that is tabular in nature. By 1998, browsers that implement tables were widespread, and Lynx was the chief remaining issue.

The discussion has been kept sufficiently general that it should be equally applicable to tables that conform to any of the various HTML recommendations and drafts.

The first edition of the document provoked interest on the usenet group comp.infosystems.www.authoring.html and brought quite a number of emails. I gladly acknowledge the considerable input, both from these explicitly named and from too many others to list. "Abigail from Mars" sent me several emails containing excellent suggestions.

This document only covers the use of the TABLE as a means to present content that is tabular in nature. Many authors (and authoring software packages) are now using the TABLE construct rather as a layout device for many different purposes: text, images, pseudo newspaper columns etc. in ways that may or may not be capable of falling back gracefully on non-table browsers. I have deliberately avoided trying to cover such situations here: they call for a quite different approach that would confuse rather than illuminate the present issue.

The problem

Let us start from a simple table, used only for the purposes of illustration.

Deutsch    British  USA
Haube      Bonnet   Hood
Kofferraum Boot     Trunk
Benzin     Petrol   Gas(oline)

It can evidently be marked up thus


if we include the optional closing tags for TH, TD and TR. Here is the result on your particular browser:

Deutsch British USA
Haube Bonnet Hood
Kofferraum Boot Trunk
Benzin Petrol Gas(oline)

However, back when some browsers did not recognise TABLE, TR, TD etc. tags at all, they ignored them, producing something like this:

DeutschBritishUSA HaubeBonnetHood KofferraumBootTrunk BenzinPetrolGas(oline)

possibly folded across several lines if a large table, (or even folded into the preceding paragraph, if you hadn't taken the precaution of closing the paragraph.)

I am assuming that your content is tabular in nature. I am also assuming that the table is small enough to fit in the browser window, and does not require multi-line entries in any of the cells.

This restriction to cell contents that each fit on one line is an over-simplification. But it will suffice for our discussion here.

Well, nowadays only very old browsers are as table-unaware as is described above. Lynx, since around version 2.5, has been somewhat table-aware, even though it doesn't actually implement the table layout. In fact, these Lynx versions will display tables pretty much as illustrated in the "Modified TABLE markup" section below, without special action by the author.

One approach that could keep your options open would be to create your source material in the form of a tab-separated data file, and then write scripts that can turn such tab-separated files into whatever kind of compromise TABLE you're currently favouring, for example one or more of the techniques below. In that way, you can leverage a single source version of each table that you produce, simply by running your latest and greatest conversion script against the original tab-separated source file.

Separate PRE and TABLE versions

If you make the same material available both as a table and as PRE, users can view whichever one their browser does best. Not a very exciting or innovative solution, but it's pretty much guaranteed to work. One might offer the choice from a higher-level document, so that the PREformatted document can be chosen without having to plough through the TABLE version first.

Some browsers will create a preformatted version for you, when you view a TABLE document and save-As "plain text": you can then pick out the table from the resulting plain text file and clap a PRE container around it. However, if it contains any < > or & characters, you'd want to convert those into entity representations.

Or use that conversion script idea that I mentioned before, starting from a tab-separated source file.

Modified TABLE markup

This technique was only useful for browsers that are completely table-unaware, so is not practically relevant nowadays. The results aren't good, but were better than nothing.

The modifications to the markup are as follows:

  1. Include white space after (or before) the contents of each table cell.
  2. Place a
    at the end of the last table cell contents on every row.

Note very carefully the correct location for the BR markup. The BR must be inside the table cell, as the last thing in the cell contents. In that position, it not only produces the desired effect, it is also syntactically valid and will pass syntax checking; placed elsewhere, it could produce bizarre effects on some browsers, quite apart from the deleterious effect when you try to syntax-check your documents.

Multiple white space provided on input is going to get collapsed in accordance with HTML's usual rules. The issue of stuffing with no-break spaces is discussed separately, later.

Now, making the discussed modifications to the sample table, we get:

Deutsch British USA
Haube Bonnet Hood
Kofferraum Boot Trunk
Benzin Petrol Gas(oline)

Here, I have added a space after the contents of each table cell (the one at the end of the rightmost cell, just before the BR, isn't actually necessary), as well as putting a BR tag in the place that I described.

A non-table browser is going to ignore the unknown tags, collect up the white space (and condense any multiple white space), and honour the BR tags.


The result (which will use your normal text font, whatever that might be) on the non-TABLE browsers that I have tried, such as the free versions (1.x) of WinWeb and MacWeb, pre-FM versions of Lynx, etc., will be somewhat as depicted here. Not ideal, but surely better than the unmodified result. This is also pretty much what later versions of Lynx do with an unmodified table anyway.

Ed Smith remarked that it may be useful to try interchanging the rows and columns of your table (if the size of the table allows this) to see whether the results are easier to read.

Although the closing tags , and are technically optional, Netscape versions have persistently behaved in unpleasant ways when these "optional" closing tags are omitted; and other nasty behaviour was seen in old browsers without them; I'd definitely recommend not omitting them.

Composite TABLE/PRE strategems

This section describes the use of deliberately invalid HTML syntax.

In spite of my misgivings over invalid HTML, I had to admit that, at the time, this technique gave remarkably effective results across a wide range of browsers. But I wouldn't recommend its use nowadays.

The technique is based on taking a pre-formatted table, and inserting table row/cell markups into it at appropriate places. Finally the whole thing is enclosed in TABLE and PRE tags, one inside the other.

Browsers that do not support tables are then expected to ignore all the table-related tags and action the PRE tags, while browsers that do support tables are expected to action the table-related tags (hopefully over-riding the effect of the PRE).

Note that HTML syntax rules are broken, since TABLE is not legal within PRE, and PRE is not legal directly inside TABLE. Although PRE is legal inside a table cell, this does not help: we need to get the entire body of the table within the scope of a single PRE.

The first version of these tests had all of the tags (TD, TH, TR) fully terminated, for the reasons already given. When viewed on Netscape, these tables were displayed below a large number of blank lines. The explanation for this behaviour was stunningly obvious, once it had been explained by Abigail: Netscape is treating the preformatted newlines, outside of a table cell, in the same way that it treats anything it finds outside of table cells - it collects up such material separately and spits it out ahead of the actual table. The solution is to move the preformatted linebreak inside the scope of the last cell of the row - or to put it another way, move the terminating from the end of one line to the beginning of the following line.

Note that, since you are dealing with pre-formatted lines, every line-break that you put into your data will be treated as significant by the browser, so you can't just put them where you please. What with the table tags etc., you'll be producing some very long HTML source lines, which you might (depending on just how you edit your source code) find hard to handle. However there is nothing to stop you from putting line breaks inside HTML tags, if you want to keep your input lines of manageable length: for example you could put at the end of one line and its final > at the start of the next line, and the browser would ignore the line break.

After doing browser tests on a wide range of then-available browsers, it was concluded that the best compromise was to put the TABLE inside the PRE, rather than vice versa. (The details are omitted as they are past-history now).

Character styles in composite PRE/TABLEs

It's perfectly viable to use character styles such as or inside such composite tables. But remember that to avoid breaking even more syntax rules, each cell of the table must be marked up separately.

A real-life case

In a usenet posting I saw a question about displaying a table of Food Service hours, and wanting it to work on Lynx. The original table had a column for each day of the week, making the table uncomfortably wide for a normal 80-col terminal window on Lynx.

However, the pattern of hours for Monday-Thursday was the same, and when I had combined those columns, the result was very suitable for the "table-in-pre" approach. Well, why not take a look for yourself. If you don't have a copy of Lynx, you might try Delorie's LynxView (I've avoided offering a precomposed submission URL, out of respect for Delorie's usage notes).

I found that this displayed happily on Win Mosaic as well as on Netscape 2.0, and adapted well to different window sizes; when Opera 2.1 became available it too was tried, and did an excellent job, again adapting well to different window widths; it displayed acceptably on UdiWWW; and it displayed just fine on various Lynx versions from 2.3BETA onwards.

Composite TAB/TABLE method

This method uses the HTML3.0 TAB tag to create tab stops, e.g and then inserts appropriate tags ahead of the table cell contents. Most browsers disregard the HTML3.0 TAB elements and format the table undisturbed, while Lynx uses the TABs instead. Note that the HTML3.0 specification measured TAB positions in ens, and Lynx interprets this by using half the number specified on the INDENT attribute (1 em = 2 ens) to determine the number of monospaced columns.

Lynx is in fact the major problem case by 1997 - a great pity since otherwise Lynx is an amazingly advanced browser for its purposes! The Lynx documentation states that TABs are only supported in a left-justified situation, so presumably this technique would not work in a centered table (?). Fine-tuning of positioning might be achieved with additional no-break spaces, although on the other hand those might produce effects on some table-capable browsers too.

There are two variants of a test table available for this test. This method produces bizarre results on browsers that implement both TABs and TABLEs, such as UdiWWW.

Use of this technique is problematical if you want to validate your documents against a public DTD, since TAB has not been in a W3C DTD since the HTML3.0 draft, but using the HTML3.0 DTD would preclude using a lot of the useful things that are in later DTDs such as HTML4.0. You might decide to produce a private DTD that added the TAB into an appropriate DTD (such as one of the HTML4.0 variants), with the obvious caveats about using private DTDs.

Nobreak-space stuffing

In June 1997, while looking through "Best Viewed with Any Browser", I stumbled on a reference to "Designing HTML Tables to Work with HTML 2.0 Browsers" which was (but is no longer) at the EFF, and had apparently been there since at least December 1996.

The key feature in the context of the present discussion was stuffing with no-break-space characters.

That article reports honestly that there is no guarantee of no-break spaces being preserved, and suggests the use of some other character (e.g dot). And, to be pedantic, that is true: the HTML4 spec, for example, explains what to do with "white space" characters (which it says the no-break space is not), then explicitly excludes any specification of what to do with other kinds of space character. However, in practice there are few browsers that do not treat non-break spaces like other printable characters, i.e occupying an appropriate-size character cell each. Consequently, it would seem that stuffing with no-break spaces as described there gives good prospects of success. Depending on the browser coverage you're aiming for, it may be possible to use   or   or actual 8-bit characters.

Single spaces within the individual cell contents should probably be kept as ordinary spaces, so that table-capable browsers have the opportunity to flow the contents onto multiple lines when appropriate.

The technique works well with left-aligned cell contents that are padded out to a pre-determined length by adding trailing no-break spaces. It can also work reasonably well when cell contents are centered by adding no-break spaces fore and aft, but on table-capable browsers these extra spaces (typically in situations where the cell contents get flowed onto more than one line) have sometimes been observed to produce an awkward-looking layout. Nevertheless, the results seem mostly very serviceable.

Here's a version of that Food service hours table again, developed with 8-bit no-break spaces. It passes syntax validation at HTML4.0 transitional.

If you want the technique to work with old graphical browsers, then you might want to mark up the table cells with to get a monospaced font, otherwise it won't line up properly; alternatively, readers may manually configure their old browser to use a monospaced font for normal text. Apart from that, this example worked on a good range of browsers, from (surprisingly!) Cello through WinWeb1 to Lynx, without doing any evident harm to the table formatting capabilities of the Big Two, Opera, arena, emacs-w3, amaya etc. I wish I had tried this variation more seriously before! (N.B only the 8-bit nobreak space works in some of the older browsers, since some of them don't understand  , and some of the really old ones don't support &#number; at all.)

Note - Lynx in numbered-links mode

Any solutions that format the page by dead-reckoning (such as the composite TABLE/PRE or the nobreak-space-stuffing methods) are liable to be thrown out of alignment if the reader is using numbered-links mode, when cells contain HTML anchor links. The TAB/TABLE method might still be able to work in that situation.

Server-side selection

It's possible in principle to detect which browser is calling (or to be exact, to detect what the browser says it is, although this could be missing or spoofed), and send alternative versions of a document (e.g separate PRE and TABLE versions, as we considered at the start). However, this requires continuing support effort in identifying browsers and their capabilities, and it has implications for the operation of caches and cache proxy servers. I don't feel that I can really recommend it, but if you decide to after all, then I'd advise a visit to Mark Nottingham's cacheing tutorial.

Client-side scripting

The idea here is that you would send a document that would be rendered correctly by any client agent - i.e a preformatted version; but you would include client-side scripting (javascript, presumably) that, when executed, would override the preformatted section with additional TABLE markup. (So-called "DHTML" techniques.)

The advantage is that you then have what is, from the server's point of view, a static document, that is fully eligible for caching, and needs no server-side selection or processing.

The disadvantage is that only those readers who have javascript enabled will get properly-formatted TABLEs. Everyone else will get plain old PRE.

Are these ideas practical?

Sceptical readers will doubtless ask whether the above ideas are practical. It is, after all, a tedious job to manufacture some of the proposed solutions by hand, and might only be worth doing for a very exposed page on which a wide browser coverage is considered to be a priority. Another example would be a head or foot fragment that you're designing so that it can be included on a large number of pages.

Well yes, it depends on how you generate your HTML and what your priorities are.

I've suggested it might be worthwhile to write a script that would take, say, a tab-delimited source file for the table, and generate the desired HTML programmatically. In this way, you can have your original data in a very convenient form (say, from another data source or easily typed in by hand) that you don't need to edit, and by modifying the conversion script in the light of experience, you can generate the exact HTML that you want.


  • For tables of the kind considered in this article, the "TABLE-in-PRE" approach gave some gratifying results, but at the expense of using invalid HTML syntax.
  • The composite TAB/TABLE method isn't conformant with any recent HTML DTD. I included the method here for interest's sake. I can't think of any practical situations nowadays (2001) where I'd actually recommend it as a solution.
  • My preference in 1998, if it seemed worth doing anything at all, was for the nobreak-space stuffing technique, and I still felt the same way about that in 2001.
  • I'm not keen on automatic server-side selection, for the reasons already given; client-side scripting should work in theory, but leaves table-capable browsers showing a preformatted table if they have javascript turned off.

But, now (2003) that most server hits from Lynx are from version 2.8.4 or from a later/development version, it seems that all of these tricks can be consigned to history.

Document history

I can't exactly recall when I started this topic, but the structure of the first edition of this writeup was essentially complete in early 1996.

I had made occasional revisions since, including in early 1997 I removed a number of references to ancient browsers that I no longer consider relevant, and added the TAB/TABLE method.

However, in May 1998 I felt that the first edition had become too long in the tooth, so I drafted a second edition.

Minor adjustments and trimming of some obsolete material since.