Opens in a new tabSkip to content
Agent LighthouseAgent Lighthouse

    Searches the text of every published page. The evidence sources themselves are not in this index — search all of them on the trusted sources page.

    GitHub ↗
    Browse checks and page contents
    content-extraction/data-tables

    Data tables properly structured

    What it checks

    AI agents use <thead> and <th> elements to understand column headers and interpret table data correctly. Without proper structure, agents cannot map cell values to their column meanings, leading to garbled data extraction in AI-generated comparisons and summaries.

    Why it matters

    Semantic lists and tables versus div soup — Content marked with ul/ol/li and table/tr/th/td survives HTML-to-markdown conversion and accessibility-tree serialization as discrete list items, rows and columns, with item and cell boundaries preserved. The same content built from nested divs collapses into undelimited running prose. An LLM must then re-infer where one item or row ends and the next begins, and cell-to-header association is lost entirely.

    Data tables with th — The presence of <th> or <thead> is what causes an extractor to classify a table as a data table rather than a layout table, and data-table classification is what exempts it from boilerplate deletion. In Mozilla Readability, a table carrying none of col, colgroup, tfoot, thead or th, and no caption or summary, is treated as layout. Its cleanup pass then becomes free to remove it, so a th-less pricing or spec table can be deleted outright before the content reaches the model. In the accessibility tree, th additionally resolves to columnheader/rowheader so header-to-cell association survives.

    Evidence

    Semantic lists and tables versus div soup

    HTML-AAM makes lists and tables first-class in the tree that agents read. table maps to table, th to columnheader or rowheader, and ul, ol and li to list and listitem roles [w3c-html-aam]. Playwright’s snapshot contents explicitly enumerate ‘lists’ and table structures [playwright-mcp-snapshots]. browser-use treats role='row'/‘cell’/‘gridcell’ as interactive targets [browser-use-clickable-elements]. On the extraction side, trafilatura ships include_tables enabled by default, and include_formatting renders structure ‘as markdown for text formats’ [trafilatura-corefunctions]. Readability applies a dedicated list-aware threshold: a node survives when more than 90% of its text sits inside list items.

    Genuinely list-shaped ul and ol therefore survive its cleanup pass, while div stacks of links do not [mozilla-readability-source]. Cloudflare’s markdown pipeline is the mass-market version of the same conversion, delivering an 80% token reduction while keeping headings, lists and tables [cloudflare-markdown-for-agents].

    Data tables with th

    Readability classifies a table as a data table when it carries col, colgroup, tfoot, thead or th, or a caption or summary. Its _cleanConditionally pass then skips it, and a table with none of those is treated as layout and deleted [mozilla-readability-source]. HTML-AAM maps th to the columnheader or rowheader roles [w3c-html-aam], over the WAI-ARIA 1.2 role set [w3c-wai-aria-1-2]. trafilatura keeps tables by default via include_tables, and renders them as markdown under include_formatting [trafilatura-corefunctions]. Markdown table syntax itself requires a header row, so a th-less table converts to a header-less or arbitrarily-headed markdown table. browser-use exposes the row, cell and gridcell roles as addressable [browser-use-clickable-elements].

    Limits

    Semantic lists and tables versus div soup — No vendor doc and no study isolates the effect of list/table markup on LLM answer accuracy — the mechanism is well documented, but the magnitude is not measured in any source located for this dossier. ARIA is an accepted substitute. A div grid carrying role='table', role='row' and role='cell' maps to the same accessibility tree nodes. ‘div soup’ with correct roles is therefore not penalised by a11y-tree consumers, and an audit that only looks for literal <table> and <ul> tags will produce false positives.

    Conversely raw-HTML consumers (which the observation-reduction study shows strong models sometimes prefer [observation-reduction-paper]) see the div tags either way. Definition lists (dl/dt/dd) in particular have no documented agent consumer beyond generic role mapping.

    Data tables with th — Two real caveats. First, th is sufficient but not necessary in Readability. The same function also classifies by size: roughly 10 or more cells, or 10 or more rows and 4 or more columns. A large th-less table survives anyway, so the deletion risk is concentrated in small tables. Second, the scope attribute is a weaker signal than th, and should be graded C on its own.

    None of the extractors examined — Readability, trafilatura, htmldate — reads @scope, and no agent harness doc mentions it. scope matters for the HTML header-association algorithm, and for screen readers. It reaches agents only indirectly, through the a11y tree on complex multi-level tables. Caption adoption is tiny (1.6% of desktop sites [web-almanac-2025-accessibility]) so caption should be advisory, not required. Recommend scoring th/thead presence, and treating scope and caption as informative sub-checks.

    How it scores

    Semantic lists and tables versus div soup — The mechanism is documented at the standard level: HTML-AAM maps table to table and th to columnheader or rowheader, Playwright’s snapshot contents enumerate lists and table structures, and browser-use treats role='row'/'cell'/'gridcell' as interactive. What is missing for an A is magnitude: no vendor document and no study isolates the effect of list and table markup on answer accuracy. ARIA is also an accepted substitute — a div grid carrying the right roles reaches the same accessibility tree — so “div soup” is not automatically a defect.

    Data tables with th — Specific, and readable in Mozilla Readability’s own source. A table counts as a data table when it carries col, colgroup, tfoot, thead or th. Its _cleanConditionally pass then skips that table. th is literally what saves a table from boilerplate deletion. Two caveats keep it at B. th is sufficient but not necessary: the same function also classifies by size, roughly ten or more cells, so the deletion risk is concentrated in small tables. And scope specifically is a weaker signal than th, which is why the audit does not weight the two alike.

    Sources