DEV Community

pooja verma
pooja verma

Posted on

Stop Importing 300KB Icon Packs - Here's How I Use Free SVG Icons Surgically in React published

Every frontend developer has done this at least once.
You need a single shopping cart icon. So you npm install heroicons or drop in FontAwesome, and now your bundle ships 400+ icons the user never sees. The Lighthouse score takes a hit, the designer asks why the site feels slow, and you spend an afternoon explaining tree-shaking to someone who didn't ask.
There's a better way — and it starts with treating icons like what they actually are: raw SVG code you control completely.

The real cost of icon libraries as npm packages
Icon packages feel convenient until they're not. Here's what actually happens when you pull in a full icon set:

Bundle bloat, even with tree-shaking, because bundlers don't always eliminate unused SVG paths cleanly
Version lock-in — upgrading a library version can silently change icon shapes or stroke weights
No customization depth — you can change color and size, but deeper path-level control requires forking

The alternative: grab individual free SVG icons, drop them inline, and own every pixel.

Where to get production-ready free SVG icons
I've been using iamvector.com as my go-to source for this. The library is genuinely free and royalty-free for commercial use — no attribution required, no licensing gotchas.
A few things worth knowing about it:

20K+ filled icons and 15K+ outlined icons — browsable at iamvector.com/all-icons/filled-icons and iamvector.com/all-icons/outlined-icons
Icons are organized by category at iamvector.com/categories — useful when you need a whole set for a feature (e-commerce, dashboard, auth flows, etc.)
You can download each icon as .svg, .png, or .webp — the SVG downloads are clean, no junk attributes
There's a Figma plugin if your team uses Figma for handoffs, so designers and devs work from the same source

The icons come in multiple visual styles — outlined, filled, and colored — so you can maintain visual consistency across a UI without fighting a third-party design system.

The pattern I actually use in React
Once you have the SVG file, here's the workflow that scales cleanly.
Step 1: Clean the SVG download
Downloaded SVGs sometimes have fixed width and height attributes, inline colors hardcoded as hex, or a fill="black" you don't want. Before adding to your project, strip those:
svg<!-- Before -->





fill="currentColor" is the key change. It makes the icon inherit color from CSS, which means you theme it with a single CSS variable instead of editing SVG attributes.
Step 2: Create a typed React component
tsx// src/components/icons/CartIcon.tsx
import { SVGProps } from 'react';

interface IconProps extends SVGProps {
size?: number;
}

export function CartIcon({ size = 24, className, ...props }: IconProps) {
return (
viewBox="0 0 24 24"
width={size}
height={size}
fill="currentColor"
className={className}
aria-hidden="true"
{...props}
>




);
}
Step 3: Use it anywhere
tsx// Inherits color from parent text color

// Explicit size

// As a button with accessible label



No import of an entire library. No runtime overhead. The icon is just markup.

Scaling this to a full icon system
Once you have more than a handful of icons, a flat folder of components gets messy. Here's the structure I use:
src/
components/
icons/
index.ts ← barrel export
CartIcon.tsx
UserIcon.tsx
SearchIcon.tsx
DashboardIcon.tsx
The index.ts just re-exports everything:
tsexport { CartIcon } from './CartIcon';
export { UserIcon } from './UserIcon';
export { SearchIcon } from './SearchIcon';
export { DashboardIcon } from './DashboardIcon';
Then imports stay clean across the app:
tsximport { CartIcon, UserIcon } from '@/components/icons';

A smarter approach: dynamic icon loader for large sets
If you end up with 50+ icons and want to lazy-load them (useful for icon pickers, admin dashboards, or any feature-gated UI), you can build a dynamic loader.
The trick is consistent file naming:
CartIcon.tsx → cart
UserIcon.tsx → user
SearchIcon.tsx → search
Then a generic component:
tsx// src/components/icons/DynamicIcon.tsx
import dynamic from 'next/dynamic';
import { ComponentType, SVGProps } from 'react';

interface DynamicIconProps extends SVGProps {
name: string;
size?: number;
}

export function DynamicIcon({ name, ...props }: DynamicIconProps) {
const IconComponent = dynamic>(
() =>
import(./${name.charAt(0).toUpperCase() + name.slice(1)}Icon).then(
(mod) => mod[${name.charAt(0).toUpperCase() + name.slice(1)}Icon]
),
{ ssr: false }
);

return ;
}
Usage:
tsx// Only loads CartIcon.js when this component renders

This is particularly useful in Next.js where you might have a settings panel or icon selector that doesn't need to ship on the critical path.

Accessibility you shouldn't skip
A lot of SVG icon implementations ignore accessibility. Two patterns worth using:
For decorative icons (next to visible text):
tsx

Add to cart

For standalone icon buttons:
tsx


The aria-hidden="true" on decorative icons prevents screen readers from announcing "image" before every icon in a list.

Bonus: inline SVG vs
You'll sometimes see SVGs loaded as image sources:
tsxCart
This works but you lose:

CSS color theming via currentColor
Hover/focus state changes without JavaScript
The ability to animate individual paths with CSS

Inline SVG components give you full CSS control. The tradeoff is a slightly larger HTML payload — worth it for interactive UI icons, less so for large illustrative graphics.
For static illustrations or logos where you don't need CSS theming, the approach is fine.

Putting it together
The workflow in practice:

Find the icon you need at iamvector.com/icons — browse by category or search by tag
Download the .svg file
Clean it: remove fixed dimensions, replace hardcoded fill with currentColor
Wrap it in a typed React component
Export from your icons barrel file

You end up with a lean, fully-typed icon system that has zero dependencies, ships exactly what you use, and gives you complete control over styling.
The icons at iamvector.com are particularly useful for this pattern because the SVG downloads are clean — no embedded raster data, no bloated metadata, just paths. The SVG editor on the site also lets you preview and tweak icons in-browser before downloading, which saves time when you're adjusting stroke weights or viewBox padding for a specific use case.

If you've been reaching for npm install every time you need an icon, try the inline approach on your next project. The bundle will thank you.

Top comments (0)