Bug in the Icon component with Plasmic CMS

What are you trying to do?
Hello everyone,

I’m trying to dynamically retrieve some data from the Plasmic CMS that consists in a SVG icon with some text.

I have to put that information in a component that has some text components and an Icon component.

When I select the SVG image that is in Plasmic CMS to put it in the Icon component, it not renders at all but instead it shows the URL of the SVG:

I need the SVG to be placed in the Icon component so I can change the color of it because I will be using several different palettes across multiple pages, so for me it’s not an option to import the SVG as an image to an Image component.

Can someone please dig into this bug so it can renders properly?

This is the link to my project component with the issue: my-project

Hi there, I looked into your project, the icon component, doesn’t seem to be taking in a URL.

I tried using the image component with the code written, and that works perfectly. You can try using the image component instead of the SVG as a workaround.

Thank you for your input. As I stated in my OP, for me, it’s not an option to use the Image component because I need to change the color of the SVG.

Can someone from Plasmic jump in to tell the internal team to fix this bug?

My apologies, I overlooked that part.

Don’t worry, your solution is the best one, however, I really need the option to change the color of the SVG :frowning:

1 Like

Hi, there is no good way of doing this in the Studio currently, a really dirty way would be to use Embed HTML with the following code:

(() => {
    function hashStringTo8Chars(str) {
        let hash = 0;
        for (let i = 0; i < str.length; i++) {
            const char = str.charCodeAt(i);
            hash = (hash << 5) - hash + char;
            hash |= 0; // Convert to 32bit integer
        }
        return (hash >>> 0).toString(36).substring(0, 8);
    }
    const url = $ctx.plasmicCmsFeatureCollection.filter( (obj) => obj.id === currentItem.feature)[0].data.icon.url
    const id = `svg-container-${hashStringTo8Chars(url)}`
    return `<div id="${id}" class="svg-icon"></div>

  <script>
    fetch('${url}')
      .then(response => response.text())
      .then(svgContent => {
        const parser = new DOMParser();
        const svgDocument = parser.parseFromString(svgContent, 'image/svg+xml');
        const svgElement = svgDocument.querySelector('svg');

        // Ensure the SVG uses currentColor
        const paths = svgElement.querySelectorAll('path');
        paths.forEach(path => path.setAttribute('fill', 'currentColor'));

        // Append the SVG to the container
        document.getElementById('${id}').appendChild(svgElement);
      })
      .catch(error => console.error('Error loading SVG:', error));
  </script>`
})()

That is going to add a script to dynamically fetch the SVG and ensure that all the paths in the svg use currentColor. This way you can simply change the color in the EmbedHTML and it should reflect in your icon.

Another options would involve changing how you register the icons in CMS/Studio.

1 Like

So, are you telling me this is not a bug? Is this an intended behavior?

Thank you for the code, but that is going to make things harder.

The other option, about changing how the icons are registered in the CMS, what do you mean? There is no option to put an SVG, only an image. Or do you refer to adding another field for the color?

Hi, I’m also interested in having a file either hosted from a CDN or embeded the SVG code directly into a JSON so that I can dynamically update an Icon; is the above situation limiting for that as well?