Skip to content
GitHub
Ui Bugs

SVG via <img> cannot inherit currentColor; index.html cannot link workspace-package assets

SVG via <img> cannot inherit currentColor; index.html cannot link workspace-package assets

Problem

The shared brand mark (Mark A) ships as SVG assets in @spectral/design-tokens/assets/. Two consumption paths silently fail:

  1. A single-ink variant using fill="currentColor" loaded with <img src={markUrl}> renders black — an SVG document loaded through <img> is an isolated document with no CSS inheritance, so currentColor resolves to the initial value.
  2. A favicon <link rel="icon" href="@spectral/design-tokens/assets/favicon.svg"> in index.html does not work — Vite resolves bare module specifiers in JS, not in HTML attribute URLs.

Root Cause

currentColor is resolved against the embedding context only when the SVG is part of the same DOM (inline <svg>) or used as a CSS mask/background with background-color: currentColor. <img>/favicon contexts isolate the SVG document. Separately, Vite’s HTML transform only rewrites relative asset paths, not workspace package specifiers.

Solution

  • Single-ink in-app marks: render an inline React component (<Mark mono> in @spectral/ui, packages/ui/src/mark.tsx) — the rects use fill="currentColor" with the 1/0.66/0.40 opacity falloff and genuinely inherit the surrounding color.
  • Favicon: import the asset URL in the entry module and inject the link at boot via the shared installFavicon(faviconUrl) helper (@spectral/ui); the favicon SVG itself uses a fixed ink, never currentColor.
  • The static mark-mono.svg asset stays for mask/static use; its header comment states the inline/mask requirement.

Prevention

  • Any “inherits currentColor” claim about an SVG asset must name the consumption mechanism (inline component or CSS mask). <img> is never it.
  • New apps adopt the brand by depending on @spectral/ui (<Mark>, installFavicon) rather than wiring raw assets.

References

  • SPEC-603 review fix commit 7034d76; merge 5570e9cb.