Skip to content

Build1 publisher2 min readPublished

Three tickets in one quarter trace back to a spec row built from divs

An accessibility audit, an extraction pass and an AI shopping assistant each found a different symptom in the same product comparison table. The markup underneath paired values to headers by position only.

The Engineer · Build desk

Illustration accompanying Three tickets in one quarter trace back to a spec row built from divs

What happened

  • A dev.to post walks through an e-commerce product comparison table built as a wrapper div, a row of header divs and a stack of value divs, with media queries folding it to one column on mobile.
  • An accessibility audit found that a screen reader announced "Battery life" and then read two numbers back to back, with nothing in the markup tying either number to a product.
  • A structured-data review found that an automated extraction pass built to feed a comparison feed could not consistently tell which value belonged to which column.
  • A one-off test asked an AI shopping assistant for one product's weight and got the other product's number back.
  • The post's proposed replacement is a table element with th scope="col" for each product and th scope="row" for each spec, carrying 18 hours and 14 hours in the battery row.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint Table markup hands the mobile collapse problem back to whoever ships the fix, because the media queries over divs were the answer to it in the first place.
  • decision An extraction suite whose fixtures give every product every spec will go green on the broken markup, so the fixture set has to include a row with a missing value before the test means anything.
  • cost Working ticket by ticket buys an aria-label, a data attribute and an extraction special case, each owned by a different team, over a structure that still pairs values to headers by position.
  • exposure The shopping assistant sits outside the team's pipeline, so its wrong answers cannot be special-cased the way the in-house extraction script's can.

CSS grid fills the boxes it is handed, in source order. The grid version in the post declares three of them with `grid-template-columns: 1fr 1fr 1fr` [13], matching a header row of Specification, Product A and Product B [14]. Give that row two values where three are expected and everything after the gap moves one column left, so Product B's 14 hours ends up under Product A [20]. The extraction pass had been reading by document order and column position the whole time, and it had been correct the whole time, until a product turned up with a spec the other one lacked [8].

That timing splits the three tickets. The screen reader complaint is present on every render, because the accessibility tree never had anything to compute a relationship from [11]. The extraction and assistant failures waited for a ragged row [8][9]. A team whose fixtures give every product every spec will watch its extraction tests pass and ship the same markup [21]. Three tools noticed before anyone opened the markup underneath the grid [7].

The table version declares the pairing. `<th scope="col">` and `<th scope="row">` tell the browser which cells each header governs, and that becomes part of the accessibility tree, computable by any consumer walking it [12]. Both versions render the same three columns, and the author's argument is that only one of them spares a consumer from inferring the pairing from where the boxes happen to sit [22].

The swap has a bill, and the post is straight about it. Table layout has historically fought responsive design, and collapsing a table onto a narrow viewport without JavaScript reflowing rows into cards has never been simple [15]. The div version got its mobile behaviour from media queries that fold it to a single column [2]. Whoever ships the table markup owns that fold again. For a photo grid or a blog card index the trade never comes up, because position is the only relationship those cells have [16].

The account is one developer's walkthrough on dev.to, published in English and Spanish [19], and it does not name the company or report what the three tools returned after the markup changed [23]. For the screen reader, the fix is definitional: scope attributes are what the tree is built from [12]. The extraction pass benefits if its parser reads table semantics instead of falling back on position [8]. The evidence that the shopping assistant would benefit is thinner, and it is this: the assistant failed in the same place the positional extractor did, on the same shifted row [9].

What to watch

  • A no-JavaScript technique for collapsing table markup on a narrow viewport would remove the reason the div version existed.
  • A follow-up reporting what the accessibility audit, the extraction pass and the assistant returned after the markup changed.
  • Any assistant vendor documenting whether it reads th scope attributes or only the rendered text.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories