85

When I try to import SVG Image then the following error shows. Which loader I have to use for importing SVG images?

./static/Rolling-1s-200px.svg 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000"><filter id="b"><feGaussianBlur stdDeviation="12" /></filter><path fill="#817c70" d="M0 0h2000v2000H0z"/><g filter="url(#b)" transform="translate(4 4) scale(7.8125)" fill-opacity=".5"><ellipse fill="#000210" rx="1" ry="1" transform="matrix(50.41098 -3.7951 11.14787 148.07886 107 194.6)"/><ellipse fill="#eee3bb" rx="1" ry="1" transform="matrix(-56.38179 17.684 -24.48514 -78.06584 205 110.1)"/><ellipse fill="#fff4bd" rx="1" ry="1" transform="matrix(35.40604 -5.49219 14.85017 95.73337 16.4 123.6)"/><ellipse fill="#79c7db" cx="21" cy="39" rx="65" ry="65"/><ellipse fill="#0c1320" cx="117" cy="38" rx="34" ry="47"/><ellipse fill="#5cb0cd" rx="1" ry="1" transform="matrix(-39.46201 77.24476 -54.56092 -27.87353 219.2 7.9)"/><path fill="#e57339" d="M271 159l-123-16 43 128z"/><ellipse fill="#47332f" cx="214" cy="237" rx="242" ry="19"/></g></svg>
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Shifut Hossain
  • 1,599
  • 3
  • 14
  • 24

14 Answers14

132

You need to provide a webpack loader that will handle SVG imports, one of the famous one is svgr.

In order to configure it to work with next, you need to add to your next.config.js file the usage of the loader, like that:

// next.config.js
    
module.exports = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/,
      issuer: {
        test: /\.(js|ts)x?$/,
       // for webpack 5 use
       // { and: [/\.(js|ts)x?$/] }
      },
      
      use: ['@svgr/webpack'],
    });

    return config;
  },
};

For more config info, check out the docs.

Don't forget to install @svgr/webpack first:

$ npm install --save-dev @svgr/webpack

Edit

I've added an issuer section which strict these svg as component only for svgs that are imported from js / ts files. This allows you to configure other behaviour for svgs that are imported from other file types (such as .css)

felixmosh
  • 32,615
  • 9
  • 69
  • 88
56

The quick way: <img> or <Image>

Not suitable for interactive SVGs or if you intend to manipulate a SVG by external CSS/JS

One can use the official next/image component or img tag (as mentioned in this answer).

You just need to move your svg file to public instead of static, and do something like this:

import Image from 'next/image';

// ...

<Image src="/Rolling-1s-200px.svg" width="2000" height="2000" />

But by using this method, the content of svg file will not be present directly in the response; the browser will get an <img src="..." ...></img> tag.

Also one needs to specify width and height, but you can calculate it from the viewbox attribute.

On Next.js v11 and above, you can also do:

import Image from 'next/image';

import Illustration from '../static/Rolling-1s-200px.svg';

// ...

<Image src={Illustration} />

// one needs to use `Illustration.src` to get the source URL
// <img src={Illustration.src} ... />

Including SVG inside HTML (for webpack-5, TS)

The accepted answer has shown how to do this with webpack-4, but since webpack-5 is now default, I'm sharing the appropriate config. You can use it after installing @svgr/webpack (yarn add -D @svgr/webpack or npm install @svgr/webpack --save-dev):

// next.config.js
// https://github.com/gregberge/svgr/issues/551#issuecomment-839772396

module.exports = {
  // other configs...

  // future: { webpack5: true }, // -- not needed since Next.js v11.0.0
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/i,
      issuer: { and: [/\.(js|ts|md)x?$/] },
      use: [
        {
          loader: '@svgr/webpack',
          options: {
            prettier: false,
            svgo: true,
            svgoConfig: { plugins: [{ removeViewBox: false }] },
            titleProp: true,
          },
        },
      ],
    });
    return config;
  },
};

If you are not using options for the loader, then you can simply write this:

use: ['@svgr/webpack']

If you are using v6 of @svgr/webpack then you need to specify SVGO config like this:

// ...

plugins: [
  {
    name: 'preset-default',
    params: {
      overrides: { removeViewBox: false },
    },
  },
],

// ...

If using typescript, you need to define proper modules (in the directory from where you are importing svg, or maybe add it at root as <some-name>.d.ts and include it tsconfig):

// index.d.ts

declare module '*.svg' {
  const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
  export default ReactComponent;
}

Then you may use it like:

import Illustration from '../static/Rolling-1s-200px.svg';

// ...

<Illustration />

Note: Next.js v11.0.1+ have declared SVGs as modules exporting any. Your custom configuration will not override the types set by next-env.d.ts unless you exclude the latter. Please refer this.

[OUTDATED (Fixed)] UPDATE :

If you are using Next.js v11.0.0, then you might be getting errors while importing SVGs. Please update to v11.0.1 or above. Please follow the workaround mentioned in this comment.

brc-dd
  • 10,788
  • 3
  • 47
  • 67
  • can i use `.svg` from `public/` directory? currently, i created `assets/` just to use relative imports using TS like `@/assets/logo.svg` but would love to use it from `public/` only. is it possible? – deadcoder0904 Jun 30 '21 at 10:38
  • @deadcoder0904 Please refer the first part of the answer. Move your SVGs to `public` and use them like this `` . You can also move your assets folder directly to `public` directory; then you would need to pass `src` as `/assets/svg-name.svg`. – brc-dd Jun 30 '21 at 10:52
  • no, i need to import it. i dont want to use `Image` component. that part is missing from your answer & its exactly what i want to do. – deadcoder0904 Jun 30 '21 at 12:25
  • 1
    @deadcoder0904 Then it's not possible. I mean you can keep a SVG in `public` or any folder, but you will need to specify whole path like `@/public/logo.svg` while importing. The second part of the answer shows this. You don't have to use `Image` component in that. – brc-dd Jun 30 '21 at 12:32
  • 1
    Note that: `assets` is just a conventional folder name, it is nothing that Next.js understands by itself. If you want to put the assets in `public` directory itself then it is also fine; you just need to change import statement: `import Logo from '@/public/logo.svg';` But please keep in mind that public folder is accessible by anyone visiting your site, so don't put anything confidential there. – brc-dd Jun 30 '21 at 12:39
  • oh yeah! next.js only understands `pages/` & `api/` i think. I use `src/` folder & `public/` folder in the same directory using aliases & I was only using aliases inside `src/` so i didn't set up aliases for `public/` & thought i could do `import Logo from '/logo.svg'` to import from `public/` but that didn't work. thanks to your both comments, it makes sense now. – deadcoder0904 Jun 30 '21 at 12:46
  • 1
    @deadcoder0904 You can use a path like this: ```"@/*": ["src/*", "public/*"]``` then `import Logo from '@/Logo.svg';` will work. – brc-dd Jun 30 '21 at 13:08
  • Still getting "You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file" and then "Error: Cannot find module '.../pages-manifest.json'" error because webpack can't read config :( Maybe it's related to sentry or next-transpile-modules but when I don't use them in config, absolute paths stop working. Guess I'll have to use prefix in imports. – VityaSchel Jul 16 '21 at 11:09
  • @VityaSchel Can you post a different question showing what all went wrong and how to reproduce it? Discussing your query here in the comment section is not beneficial for the community. And AFAIK, the second error occurs mainly due to failure in webpack build (first error). Can you try if the solutions mentioned in this thread work: https://github.com/vercel/next.js/issues/6287 – brc-dd Jul 16 '21 at 12:32
  • `` worked! – Stephane Jan 29 '22 at 15:23
  • Could you clarify a little on where exactly you add the `plugins` part of the config? I added it to the same place as the module, EG `config.plugins.push()` however Webpack panicked. SVGs did however work for me without this plugin part altogether on v6.2.1 of svgr. – Magnus Bull Jun 09 '22 at 07:55
  • 1
    @MagnusBull You don't need that if you're not using SVGO at all. I have specified this in the answer (simply `use: ['@svgr/webpack']` will work fine). However if you're using SVGO with SVGR v6, then you need to replace the plugin array of `svgoConfig` (`plugins: [{ removeViewBox: false }]` see third code block in the answer) with the shown syntax (in fifth code block). – brc-dd Jun 09 '22 at 08:12
33

Install next-images.

yarn add -D next-images

Create a next.config.js in your project

// next.config.js
const withImages = require('next-images')
module.exports = withImages()
Paul Losev
  • 969
  • 1
  • 12
  • 17
  • 14
    For those using Typescript, don't forget to add: /// into your next-env.d.ts file. – Jean Bauer Apr 19 '20 at 13:30
  • How do add my custom configurations inside withImages ? When I do ` module.exports = withImages({ reactStrictMode: true, ...rest of the cofigurations })` , the build is failing. Am I doing something wrong ? – Sanjay May 03 '22 at 12:58
20

I personally prefer next-react-svg plugin which allows to treat SVG images as React components and automatically inline them, similar to what Create React App does.

Here is how to use it:

  1. Install next-react-svg:
npm i next-react-svg
  1. Add necessary settings to next.config.js:
const withReactSvg = require('next-react-svg')
const path = require('path')

module.exports = withReactSvg({
  include: path.resolve(__dirname, 'src/assets/svg'),
  webpack(config, options) {
    return config
  }
})

The include parameter is compulsory and it points to your SVG image folder.

If you already have any plugins enabled for your Next.js, consider using next-compose-plugins to properly combine them.

  1. Import your SVGs as ordinary React components:
import Logo from 'assets/svg/Logo.svg';

export default () => (
  <Logo />
);

That's it. From now on, Next.js will be including SVG images imported this way into the rendered markup as SVG tags.

Konstantin Komelin
  • 666
  • 1
  • 8
  • 12
  • Do you know how to use next-react-svg with storybook? – Sujan Thakare Feb 25 '21 at 08:03
  • 2
    This is great thanks. If you're coming from Create React App like I am, make sure to change your import statement of the SVG. ie change `import { ReactComponent as MySvg } from 'src/assets/mysvg.svg'`. to `import MySvg from 'src/assets/mysvg.svg'` – jboxxx Mar 10 '21 at 02:48
  • 1
    That is a simple and efficient solution, Thank you. – Jerome Mar 28 '22 at 06:51
8

You can use babel-plugin-inline-react-svg

import React from 'react';
import CloseSVG from './close.svg';

const MyComponent = () => <CloseSVG />;
npm install --save-dev babel-plugin-inline-react-svg
// .babelrc
{
  "plugins": [
    "inline-react-svg"
  ]
}

Or see the link for more instructions.

Community
  • 1
  • 1
Qwerty
  • 29,062
  • 22
  • 108
  • 136
7

This worked for me without any other dependency

// In next.config.js

module.exports = {
    webpack (config, options) {
        config.module.rules.push({
            test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
            use: {
                loader: 'url-loader',
                options: {
                    limit: 100000
                }
            }
        });
        return config;
    }
};
brc-dd
  • 10,788
  • 3
  • 47
  • 67
Salil Sharma
  • 514
  • 1
  • 5
  • 14
  • 1
    This is the best answer. Pure Webpack configuration. There is no need to install anything. – Dayron Gallardo Apr 01 '20 at 20:18
  • 10
    @DayronGallardo "no need to install anything" Huh? You have to install @zeit/next-sass and @zeit/next-css – Brandon Aug 05 '20 at 18:24
  • 2
    @BrandonDuffany no you don't have to install them. The answerer has copy-pasted their own configuration, that's why there are those utility wrappers present in the code block. You don't need to use them at all. – brc-dd Oct 27 '21 at 05:31
4

You can simply import it via <img> tag.

<img src='./next.svg' alt='next' />

Just make sure that the svg is in public folder.

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Aman Bhardwaj
  • 1,509
  • 1
  • 7
  • 7
3

With Next.js 12.0.9 and Webpack 5 this works for me:

yarn add --dev url-loader @svgr/webpack
// next.config.js
module.exports = {
    webpack(config, options) {
        config.module.rules.push({
          test: /\.svg$/,
          use: ['@svgr/webpack', 'url-loader'],
        });
    
        return config;
    },
  };

kepes
  • 590
  • 2
  • 11
3

If you want to use SVG files in your code WITHOUT ANY CONFIG OR INSTALLING A DEPENDENCY and have complete control on the tag's attributes, the best solution is to convert the SVG file to JSX or TSX components.

JSX solution:

export const YourSVg = ({color, width, height}) => (
   <svg fill={color} height={height} width={width}>
    ..rest of the svg tags...
   </svg>
)

TSX solution:

   export const YourSVg:React.FC<{color:string, width:string, height:string}> =
       ({color, width, height}) => (
          <svg color={color} height={height} width={width}>
            ..rest of the svg tags...
          </svg>
    )

How to use it?

can import it like a normal component and use it same as before

for instance:

import YourSVg from '../from the path/path


<YourSVg color='red' width='10px' height='10px/>
S.Saderi
  • 4,755
  • 3
  • 21
  • 23
  • This works but requires that one shoulder an entirely new workflow for managing svg assets vs. the traditional approach of storing them in an e.g. `static/svg` directory as *.svg files. – alphazwest Aug 02 '23 at 02:14
2

How to import SVG into Next.js component?

Another solution without install any library

import React from "react";
export default function GoogleLogo() {
  return (
    <svg className="svgIcon-use" width="25" height="37" viewBox="0 0 25 25">
      <g fill="none" fillRule="evenodd">
        <path
          d="M20.66 12.693c0-.603-.054-1.182-.155-1.738H12.5v3.287h4.575a3.91 3.91 0 0 1-1.697 2.566v2.133h2.747c1.608-1.48 2.535-3.65 2.535-6.24z"
          fill="#4285F4"
        />
        <path
          d="M12.5 21c2.295 0 4.22-.76 5.625-2.06l-2.747-2.132c-.76.51-1.734.81-2.878.81-2.214 0-4.088-1.494-4.756-3.503h-2.84v2.202A8.498 8.498 0 0 0 12.5 21z"
          fill="#34A853"
        />
        <path
          d="M7.744 14.115c-.17-.51-.267-1.055-.267-1.615s.097-1.105.267-1.615V8.683h-2.84A8.488 8.488 0 0 0 4 12.5c0 1.372.328 2.67.904 3.817l2.84-2.202z"
          fill="#FBBC05"
        />
        <path
          d="M12.5 7.38c1.248 0 2.368.43 3.25 1.272l2.437-2.438C16.715 4.842 14.79 4 12.5 4a8.497 8.497 0 0 0-7.596 4.683l2.84 2.202c.668-2.01 2.542-3.504 4.756-3.504z"
          fill="#EA4335"
        />
      </g>
    </svg>
  );
}

and use:

import GoogleLogo from "./GoogleLogo";

  class Login extends React.Component {
    render() {
      return (
        <LoginLayout title="Login Page">
          <div>
            <Link href="/auth/google">
              <a className="button">
                <div>
                  <span className="svgIcon t-popup-svg">
                    <GoogleLogo />
                  </span>

                </div>
              </a>
            </Link>
          </div>
        </LoginLayout>
      );
    }
  }
Tuan Le Anh
  • 147
  • 7
1

I tried the first answer, but I got an error, so this works:

module.exports = {
webpack(config) {
  config.module.rules.push({
    test: /\.svg$/,
    use: ["@svgr/webpack"]
  });

  return config;
}};
Oleg PTP
  • 41
  • 2
0

You can use next-plugin-svgr & next-compose-plugins to clean up plugins (if you have):

// next.config.js
const withPlugins = require("next-compose-plugins");
const withSvgr = require("next-svgr");
 
module.exports = withPlugins([
  withSvgr
  // your other plugins here
]);

or just next-plugin-svgr:

// next.config.js
const withSvgr = require('next-plugin-svgr');
 
module.exports = withSvgr({
  webpack(config, options) {
    return config;
  },
});

Source: https://www.npmjs.com/package/next-plugin-svgr

igorves
  • 581
  • 3
  • 11
0

One of the simplest ways to just load the SVG as text and insert it is using the raw-loader.

So first install the npm package raw-loader via your package manager (see the docs), and then use

import mySvgContent from "!!raw-loader!../path/to/image.svg";

function MyComponent ()
{
    return (
        <div dangerouslySetInnerHTML={{__html: mySvgContent}} />
    );
}
apfelbox
  • 2,625
  • 2
  • 24
  • 26
0

If you using Nextjs 12 or newer, there is a simple solution.

In your next.config.js add this:

module.exports = {
    //another configs here
    images: {
        dangerouslyAllowSVG: true,
        contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
    }
}

i founded it Here