Skip to content

feat(table): support rowspan attribute on td/th#395

Merged
nicoburns merged 2 commits intoDioxusLabs:mainfrom
mitsuru:rowspan-support
Apr 20, 2026
Merged

feat(table): support rowspan attribute on td/th#395
nicoburns merged 2 commits intoDioxusLabs:mainfrom
mitsuru:rowspan-support

Conversation

@mitsuru
Copy link
Copy Markdown
Contributor

@mitsuru mitsuru commented Apr 20, 2026

Closes #394.

What

Add support for the rowspan attribute on <td> / <th>, which was
previously ignored (grid_row.end was hardcoded to span(1)).

How

Four changes in packages/blitz-dom/src/layout/table.rs:

  1. Parse the rowspan attribute on table cells, clamped to
    [1, 65534] per the HTML Living Standard.
  2. Apply it to grid_row.end (was span(1), now span(rowspan)).
  3. Switch grid_column.start on each cell from an explicit
    line(col+1) to auto(), so Taffy handles column placement.
  4. Set grid_auto_flow: RowDense on the table root style.

Step 4 is load-bearing. With the default sparse row-flow,
place_definite_secondary_axis_item keeps a per-item secondary-axis
cursor that carries across rows, so a cell in row N+1 starts its
column search from wherever the previous cell ended rather than from
the first track of its own row. That makes it impossible to backfill
columns freed up by rowspan cells from earlier rows.

The dense branch resets the column search to the first track on every
item. Each cell still honors its explicit grid_row, so inter-row
ordering is preserved; only the within-row column search is restarted
— exactly the behavior required for HTML table layout with rowspan.

Diff is 18 lines.

Testing

  • cargo test -p blitz-dom — all existing tests pass.
  • examples/rowspan.html (added in the first commit of this PR) —
    renders identically to Chrome after the patch. Before the patch the
    table is structurally broken (cell "6" collapses into column B,
    column C in row 3 is empty).
  • Downstream smoke: applied the equivalent backport (branch
    rowspan-support-v0.2.x)
    to fulgur via [patch.crates-io]. Its 497 unit tests
    continue to pass and its rowspan fixture renders correctly as a PDF.

Follow-ups (not in this PR)

  • rowspan="0" is clamped to 1 rather than interpreted as
    "span to end of row group" per HTML Living Standard §4.9.11.
    Browser behavior on the edge cases is inconsistent; happy to
    layer spec-exact semantics in a follow-up.
  • A v0.2.x backport of the same change is available on
    rowspan-support-v0.2.x
    if a 0.2.x point release is on the cards.

mitsuru added 2 commits April 21, 2026 03:41
Demonstrates the current broken behavior where <td rowspan=2>
is rendered as span=1, causing cells in row 3 to overlap or shift
unexpectedly.
The `<td rowspan=N>` / `<th rowspan=N>` attribute was ignored because
`grid_row.end` was hardcoded to `span(1)`. This caused cells in later
rows to overlap with or shift around rowspan cells from earlier rows.

Fix:

- Parse `rowspan` on cell nodes, clamped to [1, 65534] per HTML Standard.
- Apply it to `grid_row` span.
- Switch `grid_column.start` to `auto` so that cells use Taffy's grid
  auto-placement for column positioning.
- Set `grid_auto_flow: RowDense` on the table root.

The `dense` auto-flow is required because the default (sparse) flow
holds a per-item secondary-axis cursor across rows in
`place_definite_secondary_axis_item`. With sparse flow, a cell in row N+1
would start its column search after wherever the previous cell ended,
rather than restarting from the first track of its own row. That makes
it impossible to backfill columns left empty by rowspan cells from
earlier rows. The `dense` branch resets the search to the first track
for every item and so naturally skips columns occupied by rowspan cells
(it still honors each cell's explicit grid_row so inter-row order is
preserved).

rowspan=0 is currently clamped to 1 rather than interpreted as "span to
end of row group" as the HTML Living Standard specifies. Browser
behavior for rowspan=0 is inconsistent and this PR focuses on the
common case; deferring the spec-exact behavior as a follow-up.
@nicoburns
Copy link
Copy Markdown
Member

@mitsuru Could you rebase on top of latest main? That ought to fix CI. I don't seem have permissions to edit the PR.

That also ought to get the WPT tests running (and it would be good to see how this affects those).

@nicoburns
Copy link
Copy Markdown
Member

Hmm... running the WPT locally it's causing 2 tests to fail and none to pass which is not great...

Pass => Fail css/CSS2/tables/border-collapse-dynamic-cell-005.xht
Pass => Fail css/css-tables/visibility-collapse-rowspan-005.html

@nicoburns
Copy link
Copy Markdown
Member

Hmm... it definitely seems to help some tables on https://en.wikipedia.org/wiki/Walt_Disney_World

@nicoburns nicoburns merged commit 330d56a into DioxusLabs:main Apr 20, 2026
14 of 15 checks passed
@mitsuru mitsuru deleted the rowspan-support branch April 20, 2026 20:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Layout] Missing rowspan attribute support in table cells

2 participants