'Import .svg and resize .svg use styled-components in next.js

I am currently trying import .svg into next.js project but I failed.

I tried import .svg same way as in react project, that I created typing.d.ts and import svg like component. But it doesn't work.

declare module '*.svg' {
  import React from 'react';

  const src: string;

  export const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
  export default src;
}

Import svg example

What I need?

  • Import .svg file and change its width and height.

Has anyone had the same problem? Or did anyone manage to solve it?

Thank you



Solution 1:[1]

Maybe a solution.

  • Default option in next.js for removeViewBox is true. If you change in .svg height or width the view-box from .svg will be rest to default value.
  • If you use in your next.config.js webpack and set removeViewBox to false .svg resize start work.

A working example: stackblitz-resize-svg-next.js

  webpack(config) {
    config.module.rules.push({
      loader: '@svgr/webpack',
      options: {
        prettier: false,
        svgo: true,
        svgoConfig: {
          plugins: [
            {
              name: 'preset-default',
              params: {
                overrides: { removeViewBox: false },
              },
            },
          ],
        },
        titleProp: true,
      },
      test: /\.svg$/,
    });

    return config;
  },

If you have in .babelrc set "inline-react-svg" this solution will not work.

Solution 2:[2]

Another approach I've used, leverages svgo-loader:

  // Asset handling
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {

    // SVG handler, inlines everything under 200KB
    config.module.rules.push({
      test: /\.svg$/,
      type: 'asset',
      parser: {
        dataUrlCondition: {
          maxSize: 200 * 1024
        }
      },
      use: 'svgo-loader'
    });
    
    return config;
  },

Solution 3:[3]

I am using like that.

1- I created a Component with the SVG code that receives as a parameter width, height, or none of them

2- If it has none of them, gets the svg default width and value, else it will return the svg with its new width or height value, according to the one given

3- The default value is added to the viewBox attribute

As you can see the code below:

type SVGDoubleArrowIconProps = {    
    newWidth?: number;
    newHeight?: number;
};

export default function SVGDoubleArrowIcon({ newWidth, newHeight }: SVGDoubleArrowIconProps) {
    const defaultDimensions = { width: 50, height: 50 };
    let finalDimensions = { width: 0, height: 0 };
    if (!newWidth && !newHeight) {
        finalDimensions.width = defaultDimensions.width;
        finalDimensions.height = defaultDimensions.height;
    } else if (newWidth) {
        finalDimensions.width = newWidth;
        const ratio = newWidth / defaultDimensions.width;
        finalDimensions.height = ratio * defaultDimensions.height;
    } else if (newHeight) {
        finalDimensions.height = newHeight;
        const ratio = newHeight / defaultDimensions.height;
        finalDimensions.width = ratio * defaultDimensions.width;
    }

    return (
        <svg
            width={finalDimensions.width}
            height={finalDimensions.height}
            viewBox={`0 0 ${defaultDimensions.width} ${defaultDimensions.height}`}
            fill="none"
            xmlns="http://www.w3.org/2000/svg"
        >
            <path
                d="M56.4411 24.9827C56.4489 24.9729 56.4481 24.9588 
56.4393 24.9499L33.6545 1.93291C32.8718 1.14228 31.5944 1.14228 30.8117 
1.93291L26.3926 6.3971C25.6212 7.17637 25.621 8.43145 26.3923 
9.21088L40.6236 23.5929C41.3948 24.3723 41.3947 25.6274 40.6233 
26.4067L26.3922 40.7827C25.6209 41.5618 25.6206 42.8166 26.3915 
43.5961L30.8115 48.0654C31.5942 48.8567 32.8722 48.8569 33.6551 
48.0658L56.4404 25.042C56.4484 25.0339 56.4484 25.021 56.4404 
25.0129C56.433 25.0055 56.4324 24.9938 56.4389 24.9856L56.4411 24.9827Z"
                fill="#01FFA9"
                stroke="#0E0E0E"
                strokeWidth="2"
                strokeMiterlimit="10"
            />
            <path
                d="M32.4455 24.9817C32.4544 24.9727 32.4544 24.9582 
32.4455 24.9492L9.65446 1.93251C8.87177 1.14207 7.59451 1.14216 6.81194 
1.93271L2.39284 6.39682C1.62132 7.1762 1.62132 8.4315 2.39284 
9.21088L16.6295 23.5926C17.4012 24.3721 17.401 25.6276 16.6293 
26.4069L2.39274 40.7827C1.62122 41.5618 1.6208 42.8168 2.3918 
43.5964L6.81175 48.0656C7.59429 48.8568 8.87221 48.8571 9.65513 
48.0662L32.4462 25.043C32.4544 25.0347 32.4537 25.0211 32.4445 
25.0137C32.4354 25.0063 32.4347 24.9927 32.4429 24.9843L32.4455 24.9817Z"
                fill="#01FFA9"
                stroke="#0E0E0E"
                strokeWidth="2"
                strokeMiterlimit="10"
            />
        </svg>
    );

}

That way i can import it in any component or page and use it in:

1- New widths:

import SVGDoubleArrowIcon from '../components/SVGDoubleArrowIcon'
export default function MyPage(){
    return(<div><SVGDoubleArrowIcon width={300} /></div>);
}

2- New heights:

import SVGDoubleArrowIcon from '../components/SVGDoubleArrowIcon'
export default function MyPage(){
    return(<div><SVGDoubleArrowIcon height={300} /></div>);
}

3- Or default width and height

import SVGDoubleArrowIcon from '../components/SVGDoubleArrowIcon'
export default function MyPage(){
    return(<div><SVGDoubleArrowIcon /></div>);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mikekubn
Solution 2 serraosays
Solution 3 Germano