Tools
Tools: Making SVGs Customizable with CSS in Next.js (2026)
2026-02-21
0 views
admin
Introduction ## Why CSS Doesn't Work on Static SVGs ## Solution ## Cleaning Hard-Coded SVG Attributes that Overwrite CSS ## Solution ## Conclusion Are you confused by SVG icons that refuse to be styled with CSS? This article will give you a scalable workflow for styling SVG icons in your Next.js project. We will address the problems of: (The steps in this guide are specifically for Next.js v16+ and Typescript, but the concepts also apply to general React projects) When you try to use an SVG like this: The SVG is treated as a static external image file, similar to a PNG or JPG. You can resize it, but you cannot style or animate the contents with CSS. The root cause is not the <img> or <Image> tag itself, but the fact that the SVG is being loaded from the public/ directory which is specifically meant for static assets. To make our SVGs customizable with CSS, we will convert them to React components using SVGR and move them out of the the /public directory: Install SVGR as a dev dependency Configure SVGR in next.config.ts We are using the TurboPack asset bundler which is the fully supported default in Next.js v16. Use the SVG in your code as follows, you must ensure that the SVG is not stored in /public. Congratulations! Your SVG is now a React component rendered in the DOM as JSX, rather than a static file in /public. This makes it fully styleable, interactive, and dynamic. Some SVGs may contain hard-coded attributes that overwrite your CSS styles. In the following image, the LinkedIn icon refuses to be any color other than black. If you open the SVG file in your text editor, you can confirm this by looking for hard-coded attributes such as fill, stroke, and style: For smaller projects you can manually replace or remove hard-coded attributes that affect the appearance of the SVG. However, this may be time consuming if you have many SVG files. Here's how you can automate this process using SVGO. We will modify the SVG to inherit its color from CSS via the color property, making it compatible with both plain CSS and utility frameworks like Tailwind. Install SVGO as a dev dependency Create a file in the root directory called svgo.config.js with the following code Add a script in package.json for cleaning the SVG files, ensure that the path points to the location where your SVG files are stored Run the script to automatically modify the hard-coded attributes from your SVG files that overwrite your CSS By converting your SVGs to React components with SVGR and cleaning hard-coded attributes with SVGO, you can create fully dynamic, styleable, and maintainable icons in Next.js. This workflow ensures your SVGs respond to CSS, support animations, and remain scalable. Feel free to adapt this workflow to your own projects and share any tips or improvements you discover along the way! Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse COMMAND_BLOCK:
<img src="your_icon.svg" className="icon" /> # or <Image src="your_icon.svg" alt="GitHub" width={48} height={48} className="icon"
/> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
<img src="your_icon.svg" className="icon" /> # or <Image src="your_icon.svg" alt="GitHub" width={48} height={48} className="icon"
/> COMMAND_BLOCK:
<img src="your_icon.svg" className="icon" /> # or <Image src="your_icon.svg" alt="GitHub" width={48} height={48} className="icon"
/> COMMAND_BLOCK:
npm install --save-dev @svgr/webpack
# or use yarn
yarn add --dev @svgr/webpack COMMAND_BLOCK:
npm install --save-dev @svgr/webpack
# or use yarn
yarn add --dev @svgr/webpack CODE_BLOCK:
import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ turbopack: { rules: { "*.svg": { loaders: ["@svgr/webpack"], as: "*.js", }, }, },
}; export default nextConfig; CODE_BLOCK:
import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ turbopack: { rules: { "*.svg": { loaders: ["@svgr/webpack"], as: "*.js", }, }, },
}; export default nextConfig; CODE_BLOCK:
import GithubIcon from "@/icons/github.svg"; export default function ExternalLinks() { return ( <GithubIcon width={24} height={24} className="icon" /> );
} CODE_BLOCK:
import GithubIcon from "@/icons/github.svg"; export default function ExternalLinks() { return ( <GithubIcon width={24} height={24} className="icon" /> );
} CODE_BLOCK:
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <!-- Hard-coded fill attribute prevents color changes with CSS -->
<path d="..." fill="#0F0F0F"/> </svg> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <!-- Hard-coded fill attribute prevents color changes with CSS -->
<path d="..." fill="#0F0F0F"/> </svg> CODE_BLOCK:
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <!-- Hard-coded fill attribute prevents color changes with CSS -->
<path d="..." fill="#0F0F0F"/> </svg> COMMAND_BLOCK:
npm install -D svgo COMMAND_BLOCK:
npm install -D svgo CODE_BLOCK:
module.exports = { plugins: [ { name: "preset-default", params: { overrides: { removeViewBox: false, // keep viewBox for proper scaling }, }, }, // Remove hard-coded fill, stroke, and style attributes { name: "removeAttrs", params: { attrs: "(fill|stroke|style)", }, }, // Add fill="currentColor" to the root <svg> { name: "addAttributesToSVGElement", params: { attributes: [ { fill: "currentColor" } ], }, }, ],
}; CODE_BLOCK:
module.exports = { plugins: [ { name: "preset-default", params: { overrides: { removeViewBox: false, // keep viewBox for proper scaling }, }, }, // Remove hard-coded fill, stroke, and style attributes { name: "removeAttrs", params: { attrs: "(fill|stroke|style)", }, }, // Add fill="currentColor" to the root <svg> { name: "addAttributesToSVGElement", params: { attributes: [ { fill: "currentColor" } ], }, }, ],
}; CODE_BLOCK:
"scripts": { "clean-icons": "svgo --config=svgo.config.js [PATH_TO_SVG_DIRECTORY]/*.svg"
}, CODE_BLOCK:
"scripts": { "clean-icons": "svgo --config=svgo.config.js [PATH_TO_SVG_DIRECTORY]/*.svg"
}, COMMAND_BLOCK:
npm run clean-icons COMMAND_BLOCK:
npm run clean-icons - CSS properties not applying to static SVG images
- Hard-coded attributes within SVG files that overwrite CSS properties - Install SVGR as a dev dependency npm install --save-dev @svgr/webpack
# or use yarn
yarn add --dev @svgr/webpack
- Configure SVGR in next.config.ts import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ turbopack: { rules: { "*.svg": { loaders: ["@svgr/webpack"], as: "*.js", }, }, },
}; export default nextConfig; We are using the TurboPack asset bundler which is the fully supported default in Next.js v16.
- Use the SVG in your code as follows, you must ensure that the SVG is not stored in /public. import GithubIcon from "@/icons/github.svg"; export default function ExternalLinks() { return ( <GithubIcon width={24} height={24} className="icon" /> );
} - Install SVGO as a dev dependency npm install -D svgo
- Create a file in the root directory called svgo.config.js with the following code module.exports = { plugins: [ { name: "preset-default", params: { overrides: { removeViewBox: false, // keep viewBox for proper scaling }, }, }, // Remove hard-coded fill, stroke, and style attributes { name: "removeAttrs", params: { attrs: "(fill|stroke|style)", }, }, // Add fill="currentColor" to the root <svg> { name: "addAttributesToSVGElement", params: { attributes: [ { fill: "currentColor" } ], }, }, ],
};
- Add a script in package.json for cleaning the SVG files, ensure that the path points to the location where your SVG files are stored "scripts": { "clean-icons": "svgo --config=svgo.config.js [PATH_TO_SVG_DIRECTORY]/*.svg"
},
- Run the script to automatically modify the hard-coded attributes from your SVG files that overwrite your CSS npm run clean-icons
how-totutorialguidedev.toaimlgitgithub