Svgr: ID collisions with multiple SVG

Created on 1 Aug 2018  路  9Comments  路  Source: gregberge/svgr

With React + Webpack when I load multiple SVG in the same component (SVG is in the dom), ids are the same in multiple SVG :

First SVG result :

<svg width="158" height="185" xmlns:xlink="http://www.w3.org/1999/xlink" class="sc-fYxtnH hSLfWw">
<defs>
<linearGradient x1="0%" y1="100%" y2="0%" id="c">
...

Second SVG result :

<svg width="23" height="23" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
      <path d="M22.733 1-.267-2.09z" id="c"></path>
  </defs>
  <g fill="none" fill-rule="evenodd"> 
      <g>
          <mask id="d" fill="#fff">
              <use xlink:href="#c"></use>
          </mask>
          <path fill="#EA4335" fill-rule="nonzero" mask="url(#d)" d="M-1.07 4.705L8.023 11.5l3.744-3.189 12.838-2.038v-7.318H-1.07z"></path>
      </g>
...

The second SVG is not rendered correctly because of that. When i remove the first SVG everything works fine.

Here is my Webpack config :

{
  test: /\.svg$/,
  use: [{
    loader:'@svgr/webpack',
    options: {
      "svgoConfig": {
        "plugins": [{ "cleanupIDs": true }]
      }
    }
  }]
}

Is there something I forgot ?
Thanks

Most helpful comment

found this - https://github.com/svg/svgo/issues/674#issuecomment-324193597

the next one is a fix too

Hope it helps

 {
            test: /\.svg$/,
            use: ({resource}) => ({
                loader: '@svgr/webpack',
                options: {
                  svgoConfig: {
                    plugins: [{
                      "cleanupIDs": {
                        "prefix": `svg${hash(relative(context, resource))}`
                      }
                    }]
                  }
                }
              })
          }

All 9 comments

I met this problem several times. The best solution is to avoid using mask in SVG, if you are using Sketch you can flatten it to create a complete shape instead of using mask. Ids are not scoped this is why there is a problem in multiple SVG.

On SVGR part, we could maybe mitigate the problem by adding something that scope ids to the SVG file.

Imagine a foo.svg:

<svg width="23" height="23" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
      <path d="M22.733 1-.267-2.09z" id="c"></path>
  </defs>
</svg>

That will be transformed into Foo.js:

<svg width="23" height="23">
  <defs>
      <path d="M22.733 1-.267-2.09z" id="foo-1"></path>
  </defs>
</svg>

But the problem remain when we don't have a filename (stdin) or when we have nested directories. So the best solution is to avoid ids in inline SVG.

Seems like SVGO already has this feature see #152.

sorry for jumping in on this issue - to confirm should -

{
  test: /\.svg$/,
  use: [{
    loader:'@svgr/webpack',
    options: {
      "svgoConfig": {
        "plugins": [{ "cleanupIDs": true }]
      }
    }
  }]
}

work?

found this - https://github.com/svg/svgo/issues/674#issuecomment-324193597

the next one is a fix too

Hope it helps

 {
            test: /\.svg$/,
            use: ({resource}) => ({
                loader: '@svgr/webpack',
                options: {
                  svgoConfig: {
                    plugins: [{
                      "cleanupIDs": {
                        "prefix": `svg${hash(relative(context, resource))}`
                      }
                    }]
                  }
                }
              })
          }

Thank you @jjmax75 it works

I ran into this with linear gradients, fortunately some searching around led me here. However, this seems like a pretty disastrous default. I was able to fix mine with a simplified version of the hashing solution:

const hash = require('string-hash');

...

use: ({ resource }) => ({
  loader: '@svgr/webpack',
  options: {
    svgoConfig: {
      plugins: [{
        cleanupIDs: {
          prefix: `svg-${hash(resource)}`,
        },
      }],
    },
  },
}),

Is there a way we could get the default behavior to be more like this hashing solution? Seems like this is a fairly common problem.

Hi all,
Have anyone maintained this issue?

I have a problem. Don't work with render list component.
Example:

import AvatarSvgIcon from './avatar.svg';

render() {
   return this.prop.users.map(user => <div key={user.id}><h1>{user.name}</h1><AvatarSvgIcon /></div>)
}

I met this problem several times. The best solution is to avoid using mask in SVG, if you are using Sketch you can flatten it to create a complete shape instead of using mask. Ids are not scoped this is why there is a problem in multiple SVG.

On SVGR part, we could maybe mitigate the problem by adding something that scope ids to the SVG file.

Imagine a foo.svg:

<svg width="23" height="23" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
      <path d="M22.733 1-.267-2.09z" id="c"></path>
  </defs>
</svg>

That will be transformed into Foo.js:

<svg width="23" height="23">
  <defs>
      <path d="M22.733 1-.267-2.09z" id="foo-1"></path>
  </defs>
</svg>

But the problem remain when we don't have a filename (stdin) or when we have nested directories. So the best solution is to avoid ids in inline SVG.

Even when using the filename, hash or random to get an id, it will be repeated if is included several times in the page.

May be a note in the documentation could be useful, pointing to the Specs.

While this specification defines requirements for class, id, and slot attributes on any element, it makes no claims as to whether using them is conforming or not.

As I understand, there is no restriction to include the same ID several times, but it is not of common sense, and getElementById will match the first one in the subtree as per specs.

@gregberge do you have some recommendation?

I avoid to use ID in inline SVG, it is not reliable. Inline SVG are components, you would have the same problem in React components. Anyway there is a way to solve it. Edit by your own the SVG and use a hook to get a unique ID by component instance (example: https://gist.github.com/sqren/fc897c1629979e669714893df966b1b7).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lucasjs picture lucasjs  路  3Comments

Kosai106 picture Kosai106  路  4Comments

AskAlice picture AskAlice  路  3Comments

runeh picture runeh  路  4Comments

gwmaster picture gwmaster  路  4Comments