fix: resolve CSS custom properties (var()) in SVG descendants#575
Open
Sunyi-000 wants to merge 3 commits intobubkoo:masterfrom
Open
fix: resolve CSS custom properties (var()) in SVG descendants#575Sunyi-000 wants to merge 3 commits intobubkoo:masterfrom
Sunyi-000 wants to merge 3 commits intobubkoo:masterfrom
Conversation
When an SVG element is deep-cloned via cloneNode(true), its child elements don't go through the decorate() pipeline, so cloneCSSStyle() is never called on them. This means CSS custom properties (CSS variables) defined in external stylesheets remain as var(--name) references in the cloned SVG children, but those variable definitions are unavailable in the exported image context. Fix: after deep-cloning the SVG, walk all native/cloned descendant pairs and call cloneCSSStyle() on each. getComputedStyle() resolves var() to their actual computed values, which then get inlined on the cloned element. This restores the behaviour from before the deep-clone optimization (bubkoo#462) was introduced in v1.11.12 for SVG children, while keeping the performance benefit (no async per-child cloneNode calls) for the SVG tree structure. Fixes bubkoo#500
Contributor
|
💖 Thanks for opening this pull request! 💖 Please follow the contributing guidelines. And we use semantic commit messages to streamline the release process. Examples of commit messages with semantic prefixes:
Things that will help get your PR across the finish line:
We get a lot of pull requests on this repo, so please be patient and we will get back to you as soon as we can. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #575 +/- ##
=======================================
Coverage 66.50% 66.50%
=======================================
Files 10 10
Lines 612 612
Branches 150 150
=======================================
Hits 407 407
Misses 144 144
Partials 61 61 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Adds a dedicated test case that verifies CSS custom properties (var()) defined in external stylesheets are resolved in the serialized SVG output. The test bootstraps an SVG containing a <rect> styled with var(--rect-fill) via an external stylesheet, then checks that the exported SVG does not contain unresolved var() references in the cloned element's inline styles. Covers the new code path added in clone-node.ts (lines 83-101).
…ertion Add positive assertion that the resolved fill value (rgb(0, 128, 0)) is present in the inline style of the cloned rect. The previous assertion only checked for absence of var(), which passed vacuously when the cloned rect had no inline style at all (the old broken behavior). This assertion fails without the clone-node.ts fix and passes with it.
This was referenced Mar 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Since v1.11.12, CSS custom properties (
var()) defined in external stylesheets no longer appear in exported images when used inside SVG elements (e.g., Recharts with MUI theme colors).Root cause: PR #462 introduced a performance optimization that deep-clones SVG elements using
cloneNode(true). The early return added tocloneChildrenfor SVG nodes meanscloneCSSStyle()is never called on SVG child elements. SincecloneCSSStyleuseswindow.getComputedStyle()to resolvevar()references to their actual values, skipping it leaves CSS variables unresolved. When the SVG is serialized, those variable definitions are unavailable in the export context, so colors render as empty/transparent.Reproducible example: https://codesandbox.io/p/sandbox/vq6ml5
Fixes #500
Solution
After deep-cloning the SVG, iterate over all native/cloned descendant pairs and call
cloneCSSStyle()on each.getComputedStyle()resolvesvar(--name)to its actual computed value, which then gets inlined on the cloned element.This preserves the performance benefit of the deep-clone optimization (no async per-child
cloneNodecalls for the SVG subtree) while correctly resolving CSS variables.Why not PR #521?
PR #521 simply removes the early return for SVG elements, which causes SVG children to be re-appended to an already-populated deep-cloned SVG, resulting in duplicate children. This fix avoids that by only copying styles, not re-cloning the subtree.
Changes
src/clone-node.ts: 17 lines changed incloneChildren