Can't import SVG into Next.js
ReactjsWebpack 4next.jsReactjs Problem Overview
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>
Reactjs Solutions
Solution 1 - Reactjs
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 svg
s that are imported from other file types (such as .css
)
Solution 2 - Reactjs
<img>
or <Image>
The quick way: 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.
Solution 3 - Reactjs
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()
Solution 4 - Reactjs
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:
- Install
next-react-svg
:
npm i next-react-svg
- 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.
- 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.
Solution 5 - Reactjs
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.
Solution 6 - Reactjs
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;
}
};
Solution 7 - Reactjs
You can simply import it via <img>
tag.
<img src='./next.svg' alt='next' />
Just make sure that the svg is in public folder.
Solution 8 - Reactjs
https://stackoverflow.com/questions/56276103/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>
);
}
}
Solution 9 - Reactjs
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;
},
};
Solution 10 - Reactjs
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;
},
});
Solution 11 - Reactjs
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;
}};
Solution 12 - Reactjs
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/>