icons and dynamic SVGs
This note talks about the different ways you can import and use icons in a project.
And ways to dynamically change the color and size of them to avoid having multiple variations of the same SVG in your project.
using font file
fonts can have icons in the form of glyphs. can be considered one of the characters of the font
To use these icons install the font in your project and copy / paste the glyph.
You can change color of icon by changing font color.
font awesome
is a somewhat unique case which offers 2 methods to implement
- WebFont + CSS: classic way
- SVGs + JS: more modern approach
importing all font awesome icons or an entire icon pack is ineficient, using https://icomoon.io/ you can select individual icons and download them.
using svg files
SVGs (scalable vector graphics) are XML based text file that describes 2D vector graphics
the colors are defined inside the svg with attributes like fill
or stroke
.
Importing and using an SVG image doesn't let you dynamically change it's attributes since it is a static file with hard coded values.
html/jsx
embed an SVG directly into your HTML or JSX
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" class="icon"> <path d="M..."></path> </svg>
You can use the currentColor
value, which makes the SVG's color inherit the color
property of its parent element. For example:
<div style="color: red;"> <svg ... fill="currentColor"></svg> </div>
This option isn't very practical
svg react component
manually transform your SVG file into a react component using tools like https://react-svgr.com/playground/, https://www.svgviewer.dev/svg-to-react-jsx or transform.tools and place them in your project.
Reminder that in Nextjs you can't serve react components in the /public
dir and assets in this dir are not part of your apps final bundle.
You need to put the new component in a dir like /src/assets/images/
, making it a part of your app bundle, making it larger.
This method is recommended for small SVGs you need to be dynamic.
svgr
The svgr package automates the process of transforming SVGs into react components when you import them. There are similar packages like 'svg-inline-loader' but svgr is the most popular one.
to import SVGs as components with svgr you'll need create a dir like /src/assets/images/
since in Nextjs the svgs in the /public
dir are served statically so they aren't processed by Webpack.
Normally when you import an svg in Nextjs it calls the file-loader
tool and you get a JS object with info about the file like src
, width
and height
.
When you add the svgr configuration you tell Nextjs "Hey, when you see an import for an .svg
file from a .js
or .tsx
file, don't use your default file-loader. Instead, use SVGR to transform the SVG's code into a full-fledged React component."
Steps to add SVGR to your project: https://react-svgr.com/docs/next/
Might need to manually modify your svgs to have fill="currentColor"
instead of a hardcoded value
Example usage of imported svg components:
import MoreIcon from '@images/more-icon.svg';
...
<MoreIcon width={6} height={20} style={{ color: anchorEl ? iconColorActive : iconColorDefault }} />
The default config provided by svgr tries to import all svgs as components. This is a problem bc in my case my project already contains hundreds of cases where it imports SVGs the regular way and uses them like this:
<Image src={navProfileIcon.src} width={20} height={20} />
to fix this we have to extend the svgr config (in the next.config.ts file) even further with two options:
- query string
import svg as components when you add a query to the import
import attachIcon from '@images/attach-icon.svg?url'; // imports js obj
import attachIcon from '@images/attach-icon.svg?react'; // imports react component
- dir based
You could make it so only svgs in a certain dir are imported as components