Skip to content

2/7 Publish and pin which styling survives which export path - #303

Closed
Alek99 wants to merge 1 commit into
claude/customization-capability-matrix-vckjxg-1-mark-css-subsetfrom
claude/customization-capability-matrix-vckjxg-2-export-slot-contract
Closed

2/7 Publish and pin which styling survives which export path#303
Alek99 wants to merge 1 commit into
claude/customization-capability-matrix-vckjxg-1-mark-css-subsetfrom
claude/customization-capability-matrix-vckjxg-2-export-slot-contract

Conversation

@Alek99

@Alek99 Alek99 commented Jul 26, 2026

Copy link
Copy Markdown
Member

Stacked on #302.

The gap

custom_css was the only export asymmetry the docs named — and it is the one that was already bounded. It raises, by name, and the message says to use Engine.chromium.

The unbounded one went unmentioned. class_names={slot: ...} and styles={slot: {...}} are read only by the browser client's _applySlot. _svg.py and _raster.py read spec["dom"]["style"] and nothing else, and the SVG writer emits no class attribute anywhere. A Tailwind-styled chart exports to PNG with none of it applied and no diagnostic.

What changes

Dropping is the right behavior — raising would break every native export of a chart that carries slot classes for its live view, which is the normal way to use both surfaces together. But that is only defensible if it is written down, so it becomes a contract in three places a reader might land:

  • spec/api/export.md §9 — the engineering matrix
  • docs/styling/chrome-slots.md — the task-oriented one
  • limitations-and-alpha-status.md — for the auditor
You wrote Browser Native raster Native vector
mark / axis style= yes yes yes
chart-level style= tokens yes yes yes
styles={slot: {...}} all 23 slots dropped dropped
class_names={slot: "..."} all 23 slots dropped dropped
custom_css= yes raises raises
xy.legend(style=...) yes 6 keys 6 keys
xy.colorbar(style=...) yes dropped dropped

Two asymmetries surfaced while mapping this

xy.legend(style=...) reaches native through a second channel (legend_options["style"], six keys) that the chart-level styles={"legend": ...} spelling never touches — so two spellings that are equivalent in the browser are not equivalent in a PNG. xy.colorbar(style=...) has no native channel at all. Both are now stated rather than hidden.

Verification

tests/test_export_style_survival.py pins every row, including that the two native writers agree with each other and not merely with the page: the styled and unstyled renders of the same chart are asserted pixel-identical. A future change that teaches one writer about slot styles fails until the other learns too.


Generated by Claude Code

`custom_css` was the only export asymmetry the docs named, and it is the one
that was already bounded: it raises, by name, and the message says to use
`Engine.chromium`. The unbounded one went unmentioned. `class_names={slot: ...}`
and `styles={slot: {...}}` are read only by the browser client's `_applySlot`;
`_svg.py` and `_raster.py` read `spec["dom"]["style"]` and nothing else, and the
SVG writer emits no `class` attribute anywhere. A Tailwind-styled chart exports
to PNG with none of it applied and no diagnostic.

Dropping is the right behavior — raising would break every native export of a
chart that carries slot classes for its live view, which is the normal way to
use both surfaces — but only if it is written down. So it is now a contract in
three places a reader might actually land: `spec/api/export.md` §9 for the
engineering matrix, `docs/styling/chrome-slots.md` for the task-oriented one,
and `limitations-and-alpha-status.md` for the auditor.

`tests/test_export_style_survival.py` pins every row, including that the two
native writers agree with each other and not merely with the page: the styled
and unstyled renders of the same chart are asserted pixel-identical, so a future
change that teaches one writer about slot styles fails until the other learns
too.

Two asymmetries surfaced while mapping this and are now stated rather than
hidden. `xy.legend(style=...)` reaches native through a second channel
(`legend_options["style"]`, six keys) that the chart-level `styles={"legend":
...}` spelling never touches, so two spellings that are equivalent in the
browser are not equivalent in a PNG. `xy.colorbar(style=...)` has no native
channel at all.
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: efc6695e-bfe7-46b5-bae8-a1849e395cf4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/customization-capability-matrix-vckjxg-2-export-slot-contract

Comment @coderabbitai help to get the list of available commands.

@codspeed-hq

codspeed-hq Bot commented Jul 26, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 103 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing claude/customization-capability-matrix-vckjxg-2-export-slot-contract (f996387) with claude/customization-capability-matrix-vckjxg-1-mark-css-subset (552db46)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@Alek99 Alek99 closed this Jul 26, 2026
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.

1 participant