SVG setup
SVG files are not supported by default. To support SVG, we use SVGR (opens in a new tab) to convert SVG files to React components.
SVGR uses SVGO (opens in a new tab) that provides a default optimization preset. According to their docs,
this preset "safely removes" some values "without impacting rendering", but this is not true for viewBox
attribute that prevents svgs from scaling (see issue with removing viewBox (opens in a new tab)) and official plugin docs (opens in a new tab).
Therefore, we additionally disable removeViewBox
plugin to be able to resize icons.
For new projects, follow the setup below.
For existing projects, see the older setup at the bottom of this page.
Setup @svgr/webpack
Install @svgr/webpack
as dev dependency:
yarn add -D @svgr/webpack
Create new file svgo.config.mjs
following SVGO configuration (opens in a new tab) and
add this setup to your next.config.js
following official SVGR docs fo Next.js (opens in a new tab):
/**
* We use default preset, and additionally we disable `removeViewBox` plugin, because it prevents resizing icons by css.
*
* Docs: https://github.com/svg/svgo?tab=readme-ov-file#configuration
*/
const svgoConfig = {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false,
},
},
},
],
}
export default svgoConfig
import svgoConfig from './svgo.config.mjs'
const nextConfig = {
// ...
// Docs: https://react-svgr.com/docs/next/
webpack(config) {
// Grab the existing rule that handles SVG imports
const fileLoaderRule = config.module.rules.find((rule) => rule.test?.test?.('.svg'))
config.module.rules.push(
// Reapply the existing rule, but only for svg imports ending in ?url
{
...fileLoaderRule,
test: /\.svg$/i,
resourceQuery: /url/, // *.svg?url
},
// Convert all other *.svg imports to React components
{
test: /\.svg$/i,
issuer: fileLoaderRule.issuer,
resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, // exclude if *.svg?url
use: {
loader: '@svgr/webpack',
options: { svgoConfig },
},
},
)
// Modify the file loader rule to ignore *.svg, since we have it handled now.
fileLoaderRule.exclude = /\.svg$/i
return config
},
}
Declare svg types in declaration file:
declare module '*.svg' {
import { FC, SVGProps } from 'react'
const content: FC<SVGProps<SVGElement>>
export default content
}
declare module '*.svg?url' {
const content: any
export default content
}
Old setup for @svgr/webpack v6.5.1
Important: This setup does not work in server components, and will not work with newer versions of @svgr/webpack
.
Install @svgr/webpack
v6.5.1 as dev dependency:
yarn add -D @svgr/webpack@6.5.1
Add the following setup to your next.config.js
:
const nextConfig = {
reactStrictMode: true,
output: 'standalone',
// ...
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
issuer: /\.[jt]sx?$/,
use: {
loader: '@svgr/webpack',
options: {
svgoConfig: {
plugins: [
{
name: 'removeViewBox',
active: false,
},
],
},
},
},
})
return config
},
//...
}
Declare svg type in declaration file:
declare module '*.svg' {
import { FC, SVGProps } from 'react'
const content: FC<SVGProps<SVGElement>>
export default content
}
How to use .svg files
TODO: move this part somewhere else
- Export the .svg file from figma or you other provided .svg file.
- Place the file into assets.
- Change all instance of (stroke) color to
currentColor
in the .svg file, so the icon can be colored by css. - Export the icon in barrel file as
export { default as YourNewIcon } from './icon-name.svg'
. Make sure to follow naming convention from existing file. - Import the icon in your component and use it as a component
<YourNewIcon />
.