# Three table elements on five real pages, and all three were navigation

> Lantad's own component library states that a table is the shape an AI crawler extracts most reliably, so the claim was checked against the pages this scanner has actually stored. Counted with an HTML parser on 21 August 2026 over five real pages captured on 15 July 2026, the whole set holds three table elements, all three on one page, all three navigation boxes, and none of the five pages carries a single caption element.

- Canonical page: https://lantad.co/blog/three-tables-on-five-pages-all-navigation
- This file: https://lantad.co/blog/three-tables-on-five-pages-all-navigation.md
- Last substantive update: 2026-08-21

## Key facts

- **Published:** 2026-08-21
- **Category:** Findings
- **Author:** Lantad
- **Length:** 4200 words
- **Takeaway 1:** Counted with htmlparser2 on 21 August 2026 over the stored raw HTML of five real pages captured on 15 July 2026, four of the five pages contain zero table elements and the fifth contains three, for a set total of three tables, eleven rows, ten header cells, nine data cells and zero captions.
- **Takeaway 2:** All three table elements sit on the English Wikipedia article, each one inside a div carrying the class navbox, each table carrying the class navbox-inner, and none of them presents tabular data: they are the navigation footers of the article.
- **Takeaway 3:** The same five captures hold 1,127 list items across 204 unordered lists, 13 ordered lists and 28 definition lists, so the pages are not short of enumerated content, they simply express none of it as a table.
- **Takeaway 4:** Running the same count over the stored rendered DOM returns the identical three tables, ten header cells and zero captions, so nothing about the table shape on these pages is created or removed by JavaScript.
- **Takeaway 5:** Lantad's own extractor in core/src/extract.ts promotes a list item to main content by its tag and does not promote a table cell: measured on 21 August 2026, a two column table outside main or article yields a word count of zero, while the same facts as list items yield five.

## Summary

The file that defines the figures on this site carries an opinion in a code comment. A table, says site/src/lib/visual.ts, is rendered as semantic table markup rather than an image "because a table is the shape an AI crawler extracts most reliably". That sentence is the reason every comparison published here arrives as a grid rather than a paragraph, and it is a design decision rather than a measurement. It is also, read the other way, a claim about everybody else's pages: if a table is the most reliably extracted shape, then the pages an answer engine reads should presumably contain some.

So the claim was checked against the only pages this project can check it against. Five real pages sit in this repository as stored captures, fetched on 15 July 2026 and unchanged since, and earlier counts have already gone through their [JSON-LD](https://lantad.co/blog/three-of-five-pages-carried-json-ld), their headings and their images. This count is the table count, and it is short. Three table elements exist across all five documents. All three sit on one page. None of the three presents tabular data, and not one of the five pages carries a caption element anywhere. What an [AI crawler](https://lantad.co/glossary/ai-crawler) meets on these pages is 1,127 list items and almost no tables at all.

## How many tables five real pages actually contained

The count was run on 21 August 2026 with htmlparser2, the parser this project already depends on, walking the stored raw.html of each capture and counting elements by tag name. The five pages are astro.build, gymshark.com, the MDN reference page for HTML, webflow.com and the English Wikipedia article on web crawlers. A sixth capture in the same directory, allbirds.com, is excluded throughout because it answered the baseline fetch with HTTP 429 and stores no usable document, which is the same exclusion [the count of what JavaScript added to these pages](https://lantad.co/blog/javascript-added-no-new-crawl-paths) made for the same reason.

Across the five documents there are three table elements. astro.build has none, gymshark.com has none, the MDN reference page has none, and webflow.com has none. The Wikipedia article has three. Inside those three tables there are eleven table rows, ten header cells, nine data cells, zero caption elements and zero thead elements. That is the whole tabular surface of five real pages: nineteen cells, all of them on one document, in a set whose stored raw HTML runs to 4,615,682 bytes.

Two of those pages are worth pausing on, because they are the ones where a table would have been least surprising. The MDN reference page for HTML is a technical reference document published by a documentation team, and it carries zero tables. It expresses its element listings as 26 definition lists holding 46 terms and 46 descriptions, plus 29 unordered lists and 12 ordered ones. The Wikipedia article is the other kind of document entirely, an encyclopaedia entry maintained by volunteers using a wiki syntax that makes tables cheap to author, and its three tables are the subject of the next section. Neither authoring context produced the thing the house comment assumes is out there.

The result was verified twice by different means before it was written down, because a count of zero is the kind of number a parser bug produces. A tree walk with htmlparser2 and a plain byte search for the opening tag string returned the same figures on every file. The stored captures themselves are described on the [methodology](https://lantad.co/methodology) page, and the same corpus has been counted from three other angles already, most recently for [heading identifiers](https://lantad.co/blog/read-more-deep-links-and-heading-ids) and before that for [what its heading structure looks like](https://lantad.co/blog/an-h1-inside-a-header-counted-as-none).

## All three tables were navigation boxes, not data

The three tables on the Wikipedia article are not a small sample of tabular data. They are the article's navigation furniture, and the markup says so without ambiguity.

Each of the three is a direct child of a div carrying the class navbox, each table itself carries the class navbox-inner, and none is nested inside another table. The first holds five rows, five header cells and four data cells, and its text content opens with a block of stylesheet rules for the wiki's own navbar component. The second holds five rows, four header cells and four data cells, and its readable content is the list of crawler names that appears in the collapsible footer of the article: bingbot, Googlebot, Heritrix, HTTrack and the rest, grouped under headings reading Active, Discontinued and Types. The third holds one row, one header cell and one data cell, and its entire text is the authority control footer naming a single database.

None of the three is a grid of values. A reader scanning down a column of the second table is scanning down a category label, not a measurement, and the header cells are headers of a navigation group rather than of a data series. This matters for the argument the house comment makes, because the thing being claimed is about extraction: a table is easy for a machine to read as rows and columns because rows and columns mean something. Where the rows are navigation groups, an engine that extracts the grid faithfully has extracted a menu.

What is genuinely good here is the quality of the markup, and it deserves saying because it cuts against the easy version of this post. Every one of the ten header cells carries a scope attribute, two of them scope="col" and eight scope="row". Nothing in this set is sloppily marked up. It is carefully marked up navigation. The distinction between well formed markup and useful content is the same one that turned up when [alt text on 466 captured images](https://lantad.co/blog/alt-text-on-466-captured-images) was counted, where the attribute was frequently present and frequently empty on purpose. Markup quality and information content are separate axes, and only one of them is visible to a validator.

Rendering changes none of this. Running the identical count over the stored rendered DOM rather than the raw HTTP response returns three tables, eleven rows, ten header cells, nine data cells and zero captions, the same figures to the element. Whatever else JavaScript does to these pages, and it does plenty, it neither creates nor destroys a table. That makes the table shape a server side authoring fact on this set, unlike the [text that only exists inside a hydration payload](https://lantad.co/blog/hydration-json-scored-the-same-as-no-text), and it means a crawler that never executes a script is not missing any tables that a browser would find.

## What the pages carried instead: 1,127 list items

A page with no tables is not a page with no structure, and reporting the table count alone would give a false impression of these documents. The same five captures hold 1,127 list items in their raw HTML, distributed across 204 unordered lists, 13 ordered lists and 28 definition lists, with 46 definition terms and 48 definition descriptions.

The distribution is uneven in a way that tracks what each page is for. The MDN reference page carries the most list items at 384, and it is also the only page in the set that uses definition lists in any quantity, with 26 of the 28. gymshark.com carries 241 list items across 68 unordered lists, almost all of them product and navigation groupings. The Wikipedia article carries 315 across 67 unordered lists and the set's single ordered list that is not on MDN. webflow.com carries 150, and astro.build carries 37, the smallest count in the set and the only page under three figures.

Rendering moves these numbers slightly and in both directions, which is the more interesting half. The rendered totals are 205 unordered lists, 13 ordered lists and 1,120 list items, so the set loses seven list items overall once JavaScript has run. The movement inside that net figure is larger than the net: the MDN page falls from 29 unordered lists and 384 items to 27 and 371, while the Wikipedia article rises from 67 and 315 to 70 and 321. Client side code on one page collapses list content and client side code on another page adds it, and a crawler that does not execute scripts sees a different document from a browser on both. That gap is the thing [prose parity](https://lantad.co/glossary/prose-parity) exists to measure, and it is why a scan captures the document twice rather than once.

The practical reading for anyone writing content is not that lists are wrong. A list is a perfectly good shape for a sequence, and the [structured data](https://lantad.co/glossary/structured-data) that sits alongside it carries meaning a list cannot. The reading is narrower: when a page holds facts that genuinely have two dimensions, such as a set of options against a set of criteria, expressing them as a run of list items flattens one of those dimensions into prose order, and nothing downstream can put it back. That is a content decision made in a CMS or a component, long before any crawler arrives, and it is the same class of decision the [Shopify guide](https://lantad.co/fix/shopify) and the [Next.js guide](https://lantad.co/fix/nextjs) cover for markup that never reaches the server response at all.

## What a table element is specified to mean

Before drawing any conclusion about extraction it is worth being precise about what the element is defined to do, because the specification is narrower than the folk claim and the difference is exactly where the folk claim goes wrong.

[MDN's reference for the table element](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/table), last modified 24 April 2026, opens by stating that the element represents tabular data, being information presented in a two dimensional table comprised of rows and columns of cells containing data. That is a statement about the content, not about the rendering. Three navigation boxes satisfy the syntax of the element and not that description of it, which is the position the Wikipedia article is in.

The structural parts have their own documented purposes. The W3C Web Accessibility Initiative's [tables tutorial](https://www.w3.org/WAI/tutorials/tables/), last updated 16 February 2023, puts the machine reading case in one sentence: with structural markup, headers and data cells can be programmatically determined by software. It also states the negative directly, that tables without structural markup to differentiate and properly link between header and data cells create accessibility barriers, and it names the mechanism, that header cells must be marked up with th and data cells with td. That is the closest thing to a specification level statement that a table is machine readable, and note what it is about: the relationship between a header and the cells it governs, determined by software.

The caption is the part these five pages are missing entirely. [MDN's reference for the caption element](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/caption), also last modified 24 April 2026, says it specifies the caption or title of a table, providing the table an accessible name or accessible description, and that if included it must be the first child of its parent table element. The table reference makes the reader benefit explicit, that a caption whose value clearly and concisely describes the table's purpose helps people decide whether they need to check the rest of the table content or skip over it. A grid with no name is a grid whose subject has to be inferred from whatever prose happens to sit above it, and zero of three tables in this set carry one.

There is also a vocabulary term for the thing, which is easy to miss. [Schema.org defines a type named Table](https://schema.org/Table), described in four words as a table on a Web page, sitting in the hierarchy Thing, CreativeWork, WebPageElement, Table. It exists to let a page point at one of its own tables and say what it is. Nothing in this set uses it, and to be fair to the set, almost nothing on the web does. It is listed here because a reader working on [answer engine optimisation](https://lantad.co/glossary/aeo) will meet the type in the vocabulary and should know that its presence in schema.org is not evidence that any engine consumes it.

## Google's own guide asks for no special shape at all

The convenient conclusion from a count like this would be that pages should contain more tables, and that answer engines reward them. That conclusion is not supported by the vendor documentation, and the strongest evidence against it comes from the search engine that publishes the most about the question.

[Google's guide to optimizing for generative AI features](https://developers.google.com/search/docs/fundamentals/ai-optimization-guide), carrying Last updated 2026-07-10 UTC, addresses content shape twice and both times declines to ask for one. Its general instruction is to write content for a human audience and make sure it is well written and easy to follow, adding that people generally appreciate it when web pages are organized by paragraphs and sections, along with headings that provide a clear structure to navigate content. Paragraphs, sections and headings. Not tables, not lists, not any particular element.

The second statement is more pointed, and it is the one worth quoting when somebody sells you a formatting service. There is no requirement, the page says, to break your content into tiny pieces for AI to better understand it, because Google systems are able to understand the nuance of multiple topics on a page. Read against a market full of advice to chunk everything into extractable atoms, that is a vendor telling site owners that the atomising is not necessary. Google has been similarly direct elsewhere about tactics it says do not work, which was the subject of [the five tactics its documentation names to ignore](https://lantad.co/blog/google-names-five-geo-tactics-to-ignore).

So the honest position on the house comment that started this post is that it is an editorial preference with a plausible mechanism behind it and no vendor commitment underneath it. A table with header cells does let software determine which value belongs to which row and column, which is a real property that the W3C tutorial states and that no amount of prose can replicate. Whether any answer engine's retrieval pipeline benefits from that property is a separate question, and no page read for this post answers it. The nearest evidence in either direction is that automated rewriting for [generative engine optimisation](https://lantad.co/glossary/geo) has been measured to [degrade the document over successive rounds](https://lantad.co/blog/geo-rewriting-degraded-the-document-over-five-rounds), which is a reason to be cautious about restructuring a page for a machine on the strength of a mechanism nobody has confirmed.

The practical version of that caution: if your content is genuinely two dimensional, a table is the right element for it and always was, on accessibility grounds that are documented rather than speculative. If it is not, converting it into one to please a retrieval system is a change made on faith. Those are different decisions and the second one is the one that goes wrong.

## What this scanner does with a table, and what to check yourself

The inconvenient half of every count in this series is the part about our own code, and this one is the sharpest yet, because the file that praises tables and the file that reads them disagree.

Lantad's extractor in core/src/extract.ts sorts every run of text into a block and labels that block main, boilerplate or neutral. Only the blocks labelled main reach the corpus that the parity comparison and the word count are computed from. A block is labelled main if it sits inside a main or article element, or if its immediate container is one of the tags in a set the file calls MAIN_BLOCK_TAGS. That set holds h1 through h6, p, and li. It does not hold td, th, dt or dd. The table tags appear in the file only in a second set, BLOCK_BOUNDARY_TAGS, whose job is to flush the running text buffer so that two cells do not run together into one sentence.

Measured on 21 August 2026 rather than asserted, the effect is exact. A two column table with a header row and a data row, sitting in a plain div outside any main or article element, extracts to four neutral blocks, an empty main text and a word count of zero. The same four facts written as two list items in the same position extract to two main blocks and a word count of five. A definition list behaves like the table and yields zero. Put the identical table inside a main element and it counts, because the container promotes it, not the tags.

That is a real defect in a real product and it is worth stating without softening it. A page that puts its specifications, its pricing tiers or its comparison grid in a table that happens to sit outside main or article has those facts excluded from the corpus this scanner scores, so the grade it receives describes a document with the table removed. The rule about what [a scan actually reads](https://lantad.co/methodology) has been published all along, but nobody would have derived this from it. It is now logged, and the fix is a one line change to a set with a scoring consequence that has to be measured before it ships, which is why this post reports it rather than announcing it as done.

There is a smaller consolation in the finding, which is that on real pages it may rarely bite. All three tables in this corpus sit inside the Wikipedia article's main element, so all three are promoted by their container and none is lost. Whether that generalises is unknown, and five pages captured in one afternoon cannot answer it: this is a count, not a rate, and four of the five are homepages or reference pages rather than the specification and comparison templates where tables would most plausibly appear. The [research page](https://lantad.co/research) collects what has been measured about retrieval and citation more broadly, and the [crawlers this scanner models](https://lantad.co/bot) are listed separately from the ones it does not.

What a reader can check on their own site takes about ten minutes and needs no tool. Open the page carrying your most tabular content, view source rather than the element inspector so that you are reading what the server actually sent, and search that source for the opening table tag. If the grid you can see in the browser is not there, it is being built by script and a crawler that does not run scripts sees whatever the markup underneath it happens to be, which is usually a stack of divs. Then check whether the table sits inside a main or article element, and whether it has a caption as its first child. Our [scan of what GPTBot sees](https://lantad.co/tools/what-gptbot-sees) will show you the crawler view of the document for the first of those checks. The platform notes on [getting cited by ChatGPT](https://lantad.co/how-to-get-cited/chatgpt) cover what happens after a document is readable, which is a different problem and the one most people jump to first.

## Questions and answers

**How many tables were on the five pages Lantad captured?**

Three. Counted with htmlparser2 on 21 August 2026 over the stored raw HTML of five real pages captured on 15 July 2026, astro.build, gymshark.com, the MDN reference page for HTML and webflow.com each contain zero table elements, and the English Wikipedia article on web crawlers contains three. Inside those three tables there are eleven rows, ten header cells, nine data cells and zero caption elements. The rendered DOM of the same five pages returns identical figures.

**Do AI crawlers extract tables more reliably than prose?**

No vendor documentation read for this post says so. The W3C Web Accessibility Initiative's tables tutorial, last updated 16 February 2023, states that with structural markup headers and data cells can be programmatically determined by software, which is a real property of the markup. Whether a retrieval pipeline benefits from it is a separate and unanswered question. Google's guide to optimizing for generative AI features, carrying Last updated 2026-07-10 UTC, asks for paragraphs, sections and headings and says there is no requirement to break content into tiny pieces.

**Should I add a caption to every table?**

It is documented to help and it costs one element. MDN's caption reference, last modified 24 April 2026, states that the element provides the table an accessible name or accessible description and must be the first child of the table. MDN's table reference adds that a caption clearly and concisely describing the table's purpose helps people decide whether to read the rest of the table or skip it. None of the five pages counted for this post carries one.

**Does a Lantad scan read the text inside my tables?**

Only if the table sits inside a main or article element. The extractor in core/src/extract.ts labels a text block as main content when it is inside main or article, or when its immediate container is one of h1 to h6, p or li. The tags td, th, dt and dd are not in that set. Measured on 21 August 2026, a two column table in a plain div outside main extracts to a word count of zero, while the same facts as list items extract to five. This is a defect and it is logged rather than fixed.

---

Lantad measures whether AI crawlers can actually read a page: it fetches as a non-rendering
crawler, renders as a browser, and reports the gap. Free scan, one URL, no signup.

Method and weights: https://lantad.co/methodology | All pages as markdown: https://lantad.co/md | Crawler policy: https://lantad.co/bot
