@UmeshChaudhary For SVGs, you could rely on using the currentColor
CSS attribute in your stroke
or other color-related attribute. Then you set the text color to a design token, such as color: var(--ds-text, #000000)
. You can also use design tokens IN your SVGs if you’d prefer - it just depends on your use case.
@DeepakSharma Apologies for any confusion on this. This ticket was ONLY to support CSS variables for providing design tokens in the markup of static content macros. If there are additional CSS properties you would like to use in static content macros that are currently being filtered out, please create a new Suggestion. It was only a bug that tokens were filtered out - not generically any CSS. We have strict whitelisting for security purposes - since static content macros are rendered directly into the Confluence page and not via iframe as is the case with dynamic content macros. We can evaluate additional whitelisting based on request and importance. The good news is that enhancing this sanitization will be simpler now that we have done it for the tokens.
An example template for a static macro using design tokens would look like this:
{{!< layout}}
<span
style="border-radius:4px;padding:4px;color:var(--ds-text-accent-lime, #32CD32);border-color:var(--ds-border-danger, #FFFF00);border-style:solid;"
class="cc-eco-test-macros-block-output">
Static Content Macro using design tokens for colors
</span>
1 Like
Hello @AlexWhite ,
I am unable to implement the suggested solution for svg images. The svg is generated on server side by third party library and is sent as xhtml. Here is the sample code on how we are utilizing it.
let modifiedSvg = out.svg.replace(/fill="[^"]*"/g, 'fill="var(--ds-text, #fffff)"');
// Now you can use modifiedSvg in your XHTML
const xhtml = '<img data-theme="dark" data-color-mode="dark" style="' +
out.style +
'; height:' +
out.height +
'; width:' +
out.width +
'; font-size: inherit; display: inline-block;" src="data:image/svg+xml, ' +
encodeURIComponent(modifiedSvg) +
'"/>';
res.send(xhtml);
here is full output from svg:
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="5.399ex" height="6.176ex" style="vertical-align: -2.505ex;" viewBox="0 -1580.7 2324.5 2659.1" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" aria-labelledby="MathJax-SVG-1-Title">
<defs aria-hidden="true">
<path.....>
</defs>
<g stroke="currentColor" fill="var(--ds-text, #fffff)" stroke-width="0" transform="matrix(1 0 0 -1 0 0)" aria-hidden="true">
<g transform="translate(167,0)">
<g transform="translate(-11,0)">
<use xlink:href="#E1-MJMAIN-31" x="0" y="650"></use>
<use xlink:href="#E1-MJMAIN-33" x="0" y="-750"></use>
</g>
<g transform="translate(1490,0)">
<use xlink:href="#E1-MJMAIN-32" x="0" y="650"></use>
<use xlink:href="#E1-MJMAIN-34" x="0" y="-750"></use>
</g>
</g>
</g>
</svg>
can you take a look at the approach and provide possible solution on this one? Am i missing something?
1 Like
Thank you @AlexWhite for the example. Could you please also add an example with SVG image?
@AlexWhite we are still waiting for your response to above query. Please give us update.
@AlexWhite please update us, we are still waiting!
A common pattern we’re using for SVGs is to have them inherit the text color that the SVG lives in via currentColor
. An example Whiteboard SVG looks something like this
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3 0C1.34315 0 0 1.34315 0 3V21C0 22.6569 1.34315 24 3 24H21C22.6569 24 24 22.6569 24 21V3C24 1.34315 22.6569 0 21 0H3ZM10.2366 5.10488C11.8822 3.16021 14.2555 2.48102 15.9361 3.40114C16.1615 3.52456 16.4861 3.72402 16.7331 4.04329C17.015 4.40753 17.1546 4.87379 17.065 5.39881C16.9847 5.86907 16.7333 6.3132 16.4024 6.73569C16.2029 6.99041 15.9549 7.26189 15.6547 7.55368C17.3048 6.96438 18.7399 6.97443 19.771 7.69697C20.9549 8.52664 21.1753 9.97951 20.8804 11.2296C20.7536 11.7672 20.215 12.1001 19.6775 11.9733C19.14 11.8465 18.807 11.3079 18.9338 10.7704C19.1194 9.98373 18.8948 9.52514 18.6232 9.33484C18.3205 9.12274 17.5125 8.91139 15.8504 9.62511C15.5049 9.77347 15.094 9.78969 14.7932 9.77174C14.4679 9.75233 14.0662 9.6804 13.7094 9.50431C13.3745 9.33899 12.8184 8.9342 12.8139 8.1794C12.8099 7.52231 13.2478 7.01975 13.6469 6.67705C14.229 6.17715 14.6006 5.79262 14.8278 5.50254C14.9312 5.37049 14.9972 5.26748 15.0382 5.19112C15.0201 5.1803 14.9993 5.16839 14.9756 5.15542C14.4091 4.84527 13.0283 4.902 11.7634 6.39679C11.4066 6.81839 10.7756 6.87096 10.354 6.51421C9.93245 6.15745 9.87988 5.52647 10.2366 5.10488ZM7.25 14.25C8.49264 14.25 9.5 13.2426 9.5 12C9.5 10.7574 8.49264 9.75 7.25 9.75C6.00736 9.75 5 10.7574 5 12C5 13.2426 6.00736 14.25 7.25 14.25ZM7.25 16.25C9.59721 16.25 11.5 14.3472 11.5 12C11.5 9.65279 9.59721 7.75 7.25 7.75C4.90279 7.75 3 9.65279 3 12C3 14.3472 4.90279 16.25 7.25 16.25ZM12.5324 19L15 14.8873L17.4676 19H12.5324ZM16.2862 13.1437L19.637 18.7282C20.2368 19.728 19.5167 21 18.3507 21L11.6493 21C10.4833 21 9.76317 19.728 10.363 18.7282L13.7138 13.1437C14.2964 12.1727 15.7036 12.1727 16.2862 13.1437Z"
fill="currentColor"
/>
</svg>
And then the SVG fill inherits whichever the CSS text color
attribute is set to in the parent of the SVG.
Alternatively, you can inline the token with the CSS variable or JavaScript utility function:
import React from "react";
import { token } from "@atlaskit/tokens";
const whiteboard24Svg = () => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3 0C1.34315 0 0 1.34315 0 3V21C0 22.6569 1.34315 24 3 24H21C22.6569 24 24 22.6569 24 21V3C24 1.34315 22.6569 0 21 0H3ZM10.2366 5.10488C11.8822 3.16021 14.2555 2.48102 15.9361 3.40114C16.1615 3.52456 16.4861 3.72402 16.7331 4.04329C17.015 4.40753 17.1546 4.87379 17.065 5.39881C16.9847 5.86907 16.7333 6.3132 16.4024 6.73569C16.2029 6.99041 15.9549 7.26189 15.6547 7.55368C17.3048 6.96438 18.7399 6.97443 19.771 7.69697C20.9549 8.52664 21.1753 9.97951 20.8804 11.2296C20.7536 11.7672 20.215 12.1001 19.6775 11.9733C19.14 11.8465 18.807 11.3079 18.9338 10.7704C19.1194 9.98373 18.8948 9.52514 18.6232 9.33484C18.3205 9.12274 17.5125 8.91139 15.8504 9.62511C15.5049 9.77347 15.094 9.78969 14.7932 9.77174C14.4679 9.75233 14.0662 9.6804 13.7094 9.50431C13.3745 9.33899 12.8184 8.9342 12.8139 8.1794C12.8099 7.52231 13.2478 7.01975 13.6469 6.67705C14.229 6.17715 14.6006 5.79262 14.8278 5.50254C14.9312 5.37049 14.9972 5.26748 15.0382 5.19112C15.0201 5.1803 14.9993 5.16839 14.9756 5.15542C14.4091 4.84527 13.0283 4.902 11.7634 6.39679C11.4066 6.81839 10.7756 6.87096 10.354 6.51421C9.93245 6.15745 9.87988 5.52647 10.2366 5.10488ZM7.25 14.25C8.49264 14.25 9.5 13.2426 9.5 12C9.5 10.7574 8.49264 9.75 7.25 9.75C6.00736 9.75 5 10.7574 5 12C5 13.2426 6.00736 14.25 7.25 14.25ZM7.25 16.25C9.59721 16.25 11.5 14.3472 11.5 12C11.5 9.65279 9.59721 7.75 7.25 7.75C4.90279 7.75 3 9.65279 3 12C3 14.3472 4.90279 16.25 7.25 16.25ZM12.5324 19L15 14.8873L17.4676 19H12.5324ZM16.2862 13.1437L19.637 18.7282C20.2368 19.728 19.5167 21 18.3507 21L11.6493 21C10.4833 21 9.76317 19.728 10.363 18.7282L13.7138 13.1437C14.2964 12.1727 15.7036 12.1727 16.2862 13.1437Z"
fill={token("color.icon", "#dddddd")}
/>
</svg>
);
@UmeshChaudhary in your example, is this returned as the response from a route in your Connect app? Can you also share how it’s being rendered in your template? <img data-theme="dark" data-color-mode="dark"
won’t do anything. The data-*
tags are added automatically to the <html>
tag by the Connect/Forge theming APIs when you initialize theming. It’s not something you should add. Also it appears you’ve only added a token to the fill of your SVG and it’s set to --ds-text
which is the standard font color. Perhaps you may not realize that the token is, in fact, working correctly?
1 Like
Hi @AlexWhite,
The svg is generated on the route itself, we utilize a third party library to generate this on the fly, i.e we don’t have much control on the generated svg that’s why we need to utilize regex to override the generated svg’s parameters.
app.get('/url', addon.authenticate(), async (req, res) => {
const out = codeTogenerateSvg(); //dummy function to indicate we are getting svg here
let modifiedSvg = out.svg.replace(/fill="[^"]*"/g, 'fill="var(--ds-text, #fffff)"');
const xhtml = '<img data-theme="dark" data-color-mode="dark" style="' +
out.style +
'; height:' +
out.height +
'; width:' +
out.width +
'; font-size: inherit; display: inline-block;" src="data:image/svg+xml, ' +
encodeURIComponent(modifiedSvg) +
'"/>';
res.send(xhtml); //sending response to be rendered on confluence page
});
And we are directly sending this image html (xhtml) code as response as this is a inline-static-content-macro. That means we are not using any react.js or external html file for this.
"modules": {
"staticContentMacros": [
{
"key": "dummyKey",
"name": {"value": "name" },
"url": "/appUrl",
"description": {"value": "desc value" },
"categories": [
"visuals", "formatting"
],
"outputType": "inline",
"bodyType": "none",
"featured": true,
"parameters": [
{
"identifier": "body",
"aliases": [
"expr"
],
"name": {
"value": "name"
},
"description": {
"value": "desc"
},
"type": "string",
"required": true,
"defaultValue": ""
}
]
},
]}
Hi @AlexWhite
I tried the exact same SVG you shared, and it does not work.
Here is the code (ExpressJS backend):
app.get('/easy-math', addon.authenticate(), async (req, res) => {
let svgExampleFromAlex = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3 0C1.34315 0 0 1.34315 0 3V21C0 22.6569 1.34315 24 3 24H21C22.6569 24 24 22.6569 24 21V3C24 1.34315 22.6569 0 21 0H3ZM10.2366 5.10488C11.8822 3.16021 14.2555 2.48102 15.9361 3.40114C16.1615 3.52456 16.4861 3.72402 16.7331 4.04329C17.015 4.40753 17.1546 4.87379 17.065 5.39881C16.9847 5.86907 16.7333 6.3132 16.4024 6.73569C16.2029 6.99041 15.9549 7.26189 15.6547 7.55368C17.3048 6.96438 18.7399 6.97443 19.771 7.69697C20.9549 8.52664 21.1753 9.97951 20.8804 11.2296C20.7536 11.7672 20.215 12.1001 19.6775 11.9733C19.14 11.8465 18.807 11.3079 18.9338 10.7704C19.1194 9.98373 18.8948 9.52514 18.6232 9.33484C18.3205 9.12274 17.5125 8.91139 15.8504 9.62511C15.5049 9.77347 15.094 9.78969 14.7932 9.77174C14.4679 9.75233 14.0662 9.6804 13.7094 9.50431C13.3745 9.33899 12.8184 8.9342 12.8139 8.1794C12.8099 7.52231 13.2478 7.01975 13.6469 6.67705C14.229 6.17715 14.6006 5.79262 14.8278 5.50254C14.9312 5.37049 14.9972 5.26748 15.0382 5.19112C15.0201 5.1803 14.9993 5.16839 14.9756 5.15542C14.4091 4.84527 13.0283 4.902 11.7634 6.39679C11.4066 6.81839 10.7756 6.87096 10.354 6.51421C9.93245 6.15745 9.87988 5.52647 10.2366 5.10488ZM7.25 14.25C8.49264 14.25 9.5 13.2426 9.5 12C9.5 10.7574 8.49264 9.75 7.25 9.75C6.00736 9.75 5 10.7574 5 12C5 13.2426 6.00736 14.25 7.25 14.25ZM7.25 16.25C9.59721 16.25 11.5 14.3472 11.5 12C11.5 9.65279 9.59721 7.75 7.25 7.75C4.90279 7.75 3 9.65279 3 12C3 14.3472 4.90279 16.25 7.25 16.25ZM12.5324 19L15 14.8873L17.4676 19H12.5324ZM16.2862 13.1437L19.637 18.7282C20.2368 19.728 19.5167 21 18.3507 21L11.6493 21C10.4833 21 9.76317 19.728 10.363 18.7282L13.7138 13.1437C14.2964 12.1727 15.7036 12.1727 16.2862 13.1437Z"
fill="currentColor"
/>
</svg>`
const xhtml = '<img src="data:image/svg+xml, ' + encodeURIComponent(svgExampleFromAlex) + '"/>'
res.send(xhtml);
Below is the rendering in Confluence (see the SVG image).
Light mode
Dark mode
2 Likes
Dear @chhantyal
based on my knowledge CSS styles will never affect nodes inside an img tag. This would have solved some of our issues as well.
Hi @AlexWhite
Do you have any suggestions for how vendors can render SVG icons within <img>
tags in a way that works with both dark and light themes? As @chhantyal also reported, I found that <img>
s seemingly cannot reference CSS attributes (currentColor, or CSS variables directly).
In cases where icons are declared statically in the atlassian-connect.json, app vendors also don’t have the ability to dynamically detect the theme or ship different images, so we are stuck and the user experience will be compromised without additional work from Atlassian.
For example, can Atlassian allow vendors to supply multiple icon assets in the connect JSON for the same location?
3 Likes
I will try to summarize the issue so far.
Apps that have static macros cannot support dark mode because:
- CSS styles applied in
img
tag are stripped
- SVG: CSS attributes like
currentColor
cannot be used inside img
tag
- We cannot use
svg
tag directly, this was never supported in Confluence. The workaround was to use img
tag and provide SVG as src
(see 2)
So @AlexWhite what can we do about it? Maybe we can whitelist CSS styles in img
tag? That would be the easiest option, I guess.
I would really appreciate your prompt response.
We have now dozens of requests from customers and many bad reviews in the Marketplace listing because of this issue.
3 Likes
@AlexWhite could you please kindly check the above issues we raised?
3 Likes
I guess we are not going to hear from Alex or anyone at Atlassian anymore.
Deploy a half fix and call it a day. Where have I seen this before? Oh, well
Anyway, I guess our only hope is if someone at Atlassian thinks this ticket https://jira.atlassian.com/browse/CONFCLOUD-1762 is worth doing (it looks like a similar issue, idk). So I guess we all can vote and comment into another block hole 
3 Likes
@chhantyal et al,
Please accept my apology for further delays in a response here. Our team has been shifted around, worked on different projects and had more limited bandwidth due to summer leave. I recently took this back up and was able to give some time analyzing the use of SVGs (and tokens) in static content macros. As suggested above, there is now way to use tokens in SVGs in static content macros right now.
These are some scenarios I tried:
- Returning the SVG string from an ACE route (data URL), as the partner referred to in the community post
- Returning the SVG file from an ACE route
- Referencing a static SVG from
public/images
in the template in <img src="..." />
- Using
currentColor
for fill from the static SVG in public/images
but wrapping with a color
style
Please vote for https://jira.atlassian.com/browse/CONFCLOUD-79403 for this enhancement. Our priorities are driven by need of customers and partners like you. The more votes, the more likely we can work on this sooner.
Furthermore -Though related to https://jira.atlassian.com/browse/CONFCLOUD-1762, it’s really not the same request so wanted to make sure we tracked this specifically.
1 Like
Thank you Alex for the update, really appreciate it. Glad that it is not forgotten 
About prioritization, I would like to stress that this really needs to be done as soon as possible. We can all vote on the ticket but dark mode was released last year in Confluence and static macros still cannot fully support it.
We have tons of support request from customers as well as publicly visible negative reviews in the Marketplace listing asking us to support dark mode.
1 Like