-
Notifications
You must be signed in to change notification settings - Fork 424
HTML table processing strips inline SVG styles, causing black backgrounds in gt/svglite plots #14285
Description
Inline SVGs generated by svglite (used by gt/gtExtras for density plots, sparklines, bar charts, etc.) get black backgrounds when rendered in Quarto HTML output. The same HTML renders correctly outside Quarto.
Root cause
svglite embeds a CSS rule inside each SVG's <defs> block:
<svg>
<g class="svglite">
<defs>
<style type="text/css"><![CDATA[
.svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
fill: none;
stroke: #000000;
...
}
]]></style>
</defs>
<rect width="100%" height="100%" style="stroke: none; fill: none;"/>
<rect x="0" y="0" width="85" height="14" style="stroke-width: 0; stroke: none;"/>
<!-- ↑ no fill attribute → SVG default is black, but .svglite rule sets fill:none -->
<polygon ... style="fill: #FFFF00;"/>
</g>
</svg>The .svglite rect { fill: none } rule makes background rects transparent. Without it, SVG spec default fill: black takes effect.
handle_raw_html_as_table() in astpipeline.lua (line 150) extracts the <table>...</table> substring and passes it to pandoc.read(tableHtml, "html+raw_html") at line 167. Pandoc's HTML-to-AST conversion drops the <style> tags inside SVG <defs> — they are not part of Pandoc's table model.
The rendered HTML ends up with empty <defs> </defs> blocks and all SVG rects revert to fill: black.
Why gt's own CSS survives
gt's <style> block sits outside the <table> element (in the wrapper <div>). astpipeline.lua only extracts the <table> to </table> substring for pandoc.read(), so gt's CSS stays in the raw HTML and gets re-specified by table-rawhtml.lua. The svglite <style> tags are inside <td> cells, so they go through pandoc.read() and are lost.
Evidence
Computed fill values on the background rect:
- Standalone HTML (same gt output, no Quarto CSS):
computedFill: "none"— svglite styles intact - Quarto-rendered HTML:
computedFill: "rgb(0, 0, 0)"— styles stripped
Setting html-table-processing: none bypasses pandoc.read() and fixes the rendering.
Scope
This affects any inline SVG with embedded <style> tags inside HTML table cells — not just gt density plots. Any R package using svglite output inside tables (gtExtras sparklines, bar plots, nanoplots, etc.) would hit this.
Repro
Reprex repo: https://github.com/topepo/quarto-gt-reprex
Minimal case: any gt table using gtExtras::gt_plt_dist() or similar svglite-based plot functions, rendered in a Quarto HTML document.
Workaround: html-table-processing: none at document or cell level, or gt::tab_options(quarto.disable_processing = TRUE).
Possible fixes
- In
handle_raw_html_as_table(), detect<style>tags inside SVG elements beforepandoc.read(), extract them, and re-inject into the output HTML after conversion - Skip table processing entirely for tables that contain SVGs with embedded
<style>blocks - Promote svglite CSS to a document-level
<style>block (fragile — assumes uniform svglite rules)
Filed a companion issue on gt for the upstream side: will link once created.
Related issues
- {gt} Tables not maintaining CSS styling with html table processing. #8624 — gt tables not maintaining CSS styling with html table processing
- GT table is not correctly sized in revealjs after quarto table processing #8233 — gt table sizing broken after Quarto table processing
- tables are opaque white instead of transparent with some column layouts #8491 — tables opaque white instead of transparent with column layouts