pd4d10 / vite-plugin-svgr

Vite plugin to transform SVGs into React components
MIT License
569 stars 54 forks source link

svg ID collision #98

Open dhasdiel opened 1 year ago

dhasdiel commented 1 year ago

When using Vite plugin svgr to import multiple SVG files into a single component, I got a collision of the style because the ids how to handle this?

piotr-cz commented 11 months ago

This should be fixed after:

However, when using single file multiple times, all components still use one single ID. This is known issue for inline svgs:

See: SVGR Docs > Options > SVGO

piotr-cz commented 11 months ago

My particular case may be fixed with https://github.com/laleksiunas/inline-svg-unique-id

mobeigi commented 4 months ago

Oh boy, I ran into this issue and it took me a long time to realise this was my core problem was.

In my scenario, I was working with SVG's provided by a third party that were using letters like 'a' as ids which then of course could caused collisions with all their SVGs they provided.

Normally, if I owned the SVG's i'd try to fix this in the raw SVG's myself and inline the styles / remove ids if possible using tools such as (https://svgomg.net/) or CLI SVGO.

However, since these SVGs were provided by third parties and could be updated, I didn't want to touch the raw SVG's. The SVGs I had made use of inline styles with hard coded ids (which means that unique id solutions others had linked would not work in my case as they wouldn't fix all these edge cases).

What ended up working was to use @svgr/plugin-svgo and enable the convertStyleToAttrs and prefixIds which are disabled by default. This was enough for this project I was working on.

Config:

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import svgr from 'vite-plugin-svgr';

export default defineConfig({
  plugins: [
    react(),
    svgr({
      svgrOptions: {
        plugins: ['@svgr/plugin-svgo', '@svgr/plugin-jsx'],
        svgoConfig: {
          floatPrecision: 2,
          plugins: [
            {
              name: 'convertStyleToAttrs',
            },
            {
              name: 'prefixIds',
              params: {
                prefixIds: true,
              },
            },
          ],
        },
      },
      include: '**/*.svg?react',
    }),
  ],
});

However, I would recommend actually recreating the SVG itself if you own the SVG so it uses best practice. That way it will work for all consumers going forward without pre-processing etc.

EDIT: Turns out it wasn't quite good 'enough'. Doing this made it so each unique SVG file had its own prefix. This means I could use all of them once on a page with no issues (since each had unique ids).

However, if I used the same SVG multiple times then they would have the same id (still prefixed) and in general duplicate ids in HTML context causes issue due to ambiguity browser has to deal with. Interestingly enough, Chrome handles this case and still rendered well (so did Firefox & Android). Safari/iOS however could initially handle this case but then ran into issues after a few react renders (namely when a new DOM element was made like a modal window that contained SVGs with the same id as ones already in the DOM).

EDIT 2: Disregard the first edit. Seems like I was testing on an iOS device that had an old webkit version (2+ years with no updated). That version had a render bug in it. Updating to latest iOS (and thus webkit) fixed it.