SVGs (Scalable Vector Graphics) are a popular choice for us web developers and designers due to their scalability and flexibility. Next.js offers several options for incorporating SVGs into your projects. In this article, we will explore these options, discuss their pros and cons, and demonstrate how to utilize SVGs within Next.js.
Using an External SVG File
One straightforward method is to import the SVG file directly into your page. Let's assume we have an SVG file named bugIcon.svg
import export default function SomePage(}) { return ( <div className="mb-32 w-full text-white"> <Image src="/bugIcon.svg" alt="Hero Icons Bug" width={30} height={30} className="text-white fill-white stroke-white" style={{ color: "white", fill: "white", stroke: "white" }} /> I'm here, I swear it! </div> ) }
Unfortunately, if we do it like this, we cannot manipulate the styling as you can see. No matter what you do, inline style or tailwindcss, it won't work. You can go in and directly change the color within the SVG, but what about later when you want to edit it? What about dark mode?
I can hear some of you saying why not use 'invert' (filter: invert(100%) for normal CSS), what if we wanted anything other than white or different colours for dark mode?
I think it's time to try another method.
SVG components
There some honourable mentions such as SVGR or having it directly in your page, but the best way to handle SVGs within Next.js is to create an icon component.
const BugIcon = () => { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" className="w-8 h-8" height={32} width={32} > <path strokeLinecap="round" strokeLinejoin="round" d="M12 12.75c1.148 0 2.278.08 3.383.237 1.037.146 1.866.966 1.866 2.013 0 3.728-2.35 6.75-5.25 6.75S6.75 18.728 6.75 15c0-1.046.83-1.867 1.866-2.013A24.204 24.204 0 0112 12.75zm0 0c2.883 0 5.647.508 8.207 1.44a23.91 23.91 0 01-1.152 6.06M12 12.75c-2.883 0-5.647.508-8.208 1.44.125 2.104.52 4.136 1.153 6.06M12 12.75a2.25 2.25 0 002.248-2.354M12 12.75a2.25 2.25 0 01-2.248-2.354M12 8.25c.995 0 1.971-.08 2.922-.236.403-.066.74-.358.795-.762a3.778 3.778 0 00-.399-2.25M12 8.25c-.995 0-1.97-.08-2.922-.236-.402-.066-.74-.358-.795-.762a3.734 3.734 0 01.4-2.253M12 8.25a2.25 2.25 0 00-2.248 2.146M12 8.25a2.25 2.25 0 012.248 2.146M8.683 5a6.032 6.032 0 01-1.155-1.002c.07-.63.27-1.222.574-1.747m.581 2.749A3.75 3.75 0 0115.318 5m0 0c.427-.283.815-.62 1.155-.999a4.471 4.471 0 00-.575-1.752M4.921 6a24.048 24.048 0 00-.392 3.314c1.668.546 3.416.914 5.223 1.082M19.08 6c.205 1.08.337 2.187.392 3.314a23.882 23.882 0 01-5.223 1.082" /> </svg> ); }; export default BugIcon;
We remove any properties that come with our SVG. This was the original SVG tag.
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" className="w-6 h-6" >
I removed strokeWidth, stroke and fill. We will control all of these with tailwindcss. I added the height and width properties directly, even though we will manage them tailwindcss. This is so that we don't go any ugly loading content shift.
Of course, we don't want to go into the SVG file every time we want to edit it. So we need to handle the props.
const BugIcon = ({ className, height, width }) => { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" className={`${className || "w-8 h-8"}`} height={height || 32} width={width || 32} > <path strokeLinecap="round" ... /> </svg> ); }; export default BugIcon;
We need some defaults as we don't want to have to explicitly set them if we don't need to. Simply using this || operator allows us to add those defaults for when the properties are undefined.
import BugIcon from "./bugIcon";
Now we use the components and provide it the properties needed.
<BugIcon className="stroke-black dark:stroke-white" height={80} width={80} />
Now our parent component is free of clutter and we have the ability to manipulate the SVG freely.