Safari/WebKit: writing sub-cell offset custom properties via CSSOM rule.style is not reliably reflected in computed style on the slotted table
- Dominant language
- JavaScript
- Stars
- 403
- Forks
- 43
- Avg merge
- 3m
- Merged PRs (30d)
- 1
Description
## Summary
The sub-cell scroll offset (`--regular-table--transform-y`, `--regular-table--clip-y`, etc., defined by `sub-cell-offsets.less` on `:host ::slotted(table)` and applied via `_update_sub_cell_offset` mutating a `CSSStyleRule.style` object in the shadow root's adopted stylesheet) can be written correctly but never actually take visible effect on Safari/WebKit.
## Reproduction
Instrumented `_update_sub_cell_offset` to log, on every call: the computed `y_offset`, the exact string passed to `setProperty`, and an immediate `getPropertyValue` read-back off the same `_sub_cell_rule.style` object. Every logged call showed the read-back exactly matching what was written - confirming the CSSOM write itself always succeeds, including the final call before the symptom was captured (`start_row: 67.68`, `y_offset: 17.00000000000017`, both written and immediately read back as `-17.00000000000017px`).
In the same diagnostic capture, `getComputedStyle()` on the actual live, slotted `` element read `--regular-table--transform-y` as `0px` - not the value just confirmed written to the rule. Visually this manifests as e.g. the last row of a sorted, scrolled-to-the-true-bottom grid staying clipped indefinitely, with no further scroll able to correct it (the write "succeeds" every time, it just never reaches layout).
We could not find an existing WebKit bug that matches this exactly (closest candidates we checked - container-query-related `::slotted()` crashes, `::slotted()` + flexbox layout, `::slotted()` + ID selectors - are all different issues). It's possible this is specific to the combination of: a **per-instance** `CSSStyleSheet` (not shared/global), adopted onto the shadow root, containing a rule targeting `::slotted()`, whose declaration block is then mutated **imperatively** via `CSSStyleRule.style.setProperty()` rather than by toggling a class/attribute WebKit recognizes as needing recalc.
## Status: workaround, not root cause
This is very likely a WebKit engine bug rather than something fixable in `regular-table`'s own logic (the computed values are already correct - the browser just isn't applying them). Our fork works around it by also setting the same properties directly on the slotted table's own inline style in `_update_sub_cell_offset`:
```ts
const table = this.table_model?.table;
if (table) {
table.style.setProperty(CLIP_X, `${x_offset}px`);
table.style.setProperty(CLIP_Y, `${y_offset}px`);
table.style.setProperty(TRANSFORM_X, `${-x_offset}px`);
table.style.setProperty(TRANSFORM_Y, `${-y_offset}px`);
}
```
An inline style mutation on the element always invalidates its own computed style, sidestepping the `::slotted()` cascade path entirely. This resolved the symptom in our testing (macOS Safari / WKWebView).
Filing here (rather than only reporting to WebKit) since anyone using this library's sub-cell scrolling feature on Safari could be hitting this silently, and the inline-style workaround above is a reasonable low-risk addition regardless of whether it's ultimately a WebKit bug or something in how the adopted stylesheet is set up. Happy to open this as a PR if that's useful, though I'd flag it as "safe defensive addition" rather than "confirmed root-cause fix" given the underlying WebKit behavior is still unexplained.
Contributor guide
Research direction
Start at _update_sub_cell_offset and inspect how table_model.table exposes the live slotted table. Reproduce the CSSOM write and computed-style mismatch in Safari or WKWebView, then verify that the four offset properties take effect on the table itself and that the true-bottom scrolling symptom is resolved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100