Search code examples
csssvg

SVG Sprite with style attributes on different grouping tags


I have a sprite map SVG, and example usage is like this:

<svg aria-hidden="true" class="block w-full h-full block"><use xlink:href="/src/assets/sprite.svg?t=123#triangle"></use></svg>

This loads the triangle SVG in Shadow DOM like so:

<svg viewBox="0 0 1920 1080" fill="currentColor" id="battery_distributor"><path d="M150 5 75 200h150Z"></path></svg>

However, the triangle SVG is set like this:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1920 1080">
    <path d="M150 5 L75 200 L225 200 Z" style="fill: none; stroke: green; stroke-width: 3" />
</svg>

But it appears filled in as black on the output DOM via the sprite.

My guess is because the vite-svg-sprite-wrapper plugin I use for building the sprite map https://github.com/vshepel/vite-svg-sprite-wrapper is stripping the style attribute away.

Is there another method to be able to add SVG files via one single React Typescript component in Vite which still support custom style attributes on different grouping g tags?

The docs for that plugin link to this SVG Sprite tool https://github.com/svg-sprite/svg-sprite/

Which in turn mentions it uses svgo - https://github.com/svg/svgo


EDIT: The actual SVG has something like this, just fake path numbers. The issue is that the first grouping child using stroke displays correctly but the 2nd grouping child using fill does not display, as I have color: transparent to try to avoid the weird background clipping grey colour:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1920 1080">
    <g>
        <g transform="matrix(1,0,0,1,200,500)" opacity="1" style="display: block;">
            <g opacity="1" transform="matrix(1,0,0,1,0,0)">
                <path stroke-linecap="round" stroke-linejoin="round" fill-opacity="0" stroke-dasharray="10"
                    stroke="rgb(0,0,0)" stroke-opacity="0.35" stroke-width="3"
                    d="M-20, 100">
                </path>
            </g>
            <g opacity="1" transform="matrix(1,0,0,1,0,0)">
                <path stroke-linecap="round" stroke-linejoin="round" fill-opacity="0" stroke-dasharray="10"
                    stroke="rgb(180,211,46)" stroke-opacity="1" stroke-width="3"
                    d="M-20, 100">
                </path>
            </g>
        </g>
        <g transform="matrix(1,0,0,1,1,0)" opacity="1" style="display: block;">
            <g opacity="1"
                transform="matrix(1,0,0,1,1,0)">
                <path fill="rgb(0,0,0)" fill-opacity="0.35"
                    d="M1, -28z">
                </path>
            </g>
            <g opacity="1"
                transform="matrix(0, 0, 1, 1)">
                <path fill="rgb(180,211,46)" fill-opacity="1"
                    d="M1, -28z">
                </path>
            </g>
        </g>
    </g>
</svg>

Solution

  • Found a fix, so basically the vite-svg-sprite-wrapper Vite plugin is a wrapper for svg-sprite but this uses svgo

    After reading through all the docs, there is a sprite config option which configures how svg-sprite works. In that it has an option for configuring the tranformation of svgo using shape.transform

    I want to keep the same default preset, and only ovveride the removeStyleElemets plugin for svgo, thus my final code is now:

    ViteSvgSpriteWrapper({
            icons: 'public/animations/*.svg',
            outputDir: 'src/assets',
            sprite: {
              shape: {
                transform: [{
                  svgo: {
                    plugins: [{
                      name: 'preset-default',
                      params: {
                        overrides: {
                          removeStyleElement: false,
                        }
                      }
                    }]
                  }
                }]
              }
            }
          }),
    

    ...and this works, the style attributes are kept on the g tags.