Using SVGs in React and Next.js: Complete Integration Guide
Master SVG integration in React and Next.js applications. Learn import methods, component patterns, optimization, and best practices for modern web development.

Founder of VectoSolve
Self-taught developer, founder and sole developer of VectoSolve since 2024. He builds the conversion engine and the cutting, embroidery and 3D printing exports.
How this article was made: drafted with AI assistance, then edited and fact-checked before publication. About the author
Try it on your own file
Free preview, no signup. Drop an image and see the vector before deciding anything.
Key Takeaways
- React offers four main SVG import methods: image import, inline SVG, SVGR components, and dynamic imports
- SVGR with Next.js webpack config gives you the best balance of developer experience and runtime control
- Reusable icon components with TypeScript props (size, color, className) keep your codebase DRY
- Framer Motion integrates natively with SVG elements for spring-based path and shape animations
-
Always add
aria-labeloraria-hiddento SVG icons for screen reader accessibility
SVG in Modern React Development
SVGs are essential for modern React applications, offering crisp graphics at any scale. This guide covers every method of using SVGs in React and Next.js projects.
Import Methods
1. Standard Image Import
Simplest approach:
import logo from './logo.svg';
function Header() {
return <img src={logo} alt="Logo" className="logo" />;
}
Pros: Simple, familiar
Cons: No styling/manipulation access
2. Inline SVG Components
Full control:
function Icon() {
return (
<svg viewBox="0 0 24 24" className="icon">
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5"/>
</svg>
);
}
Pros: Full CSS/JS access
Cons: Verbose, can't easily change source
3. SVGR (React Component)
Import as component:
import { ReactComponent as Logo } from './logo.svg';
function Header() {
return <Logo className="logo" fill="currentColor" />;
}
Pros: Best of both worlds
Cons: Requires configuration
4. Dynamic Import
For code splitting:
import dynamic from 'next/dynamic';
const DynamicIcon = dynamic(() => import('./icons/chart.svg'));
function Dashboard() {
return <DynamicIcon />;
}
Pro Tip: For most React projects, SVGR is the recommended approach. It lets you import SVGs as React components with full prop support while keeping SVG files separate for easy editing in design tools.
SVGR Configuration
Next.js Setup
// next.config.js
module.exports = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack'],
});
return config;
},
};
With URL Fallback
// next.config.js
module.exports = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
issuer: /\.[jt]sx?$/,
use: [
{
loader: '@svgr/webpack',
options: {
svgoConfig: {
plugins: [{
name: 'removeViewBox',
active: false
}]
}
}
},
'url-loader'
],
});
return config;
},
};
A Full Year of Conversions for $49
Starter Annual: 25 conversions every month, $49 for the whole year. That is about $4.08 a month · Cancel anytime
Get the Annual DealComponent Patterns
Reusable Icon Component
interface IconProps {
name: string;
size?: number;
color?: string;
className?: string;
}
export function Icon({ name, size = 24, color = 'currentColor', className }: IconProps) {
return (
<svg
width={size}
height={size}
fill={color}
className={className}
>
<use href={`/sprites.svg#${name}`} />
</svg>
);
}
// Usage
<Icon name="search" size={20} color="#333" />
Icon Library Component
// icons/index.tsx
import { FC, SVGProps } from 'react';
interface IconComponentProps extends SVGProps<SVGSVGElement> {
size?: number;
}
const createIcon = (path: string): FC<IconComponentProps> => {
return function IconComponent({ size = 24, ...props }) {
return (
<svg
viewBox="0 0 24 24"
width={size}
height={size}
fill="currentColor"
{...props}
>
<path d={path} />
</svg>
);
};
};
export const SearchIcon = createIcon('M15.5 14h-.79l-.28-.27...');
export const HomeIcon = createIcon('M10 20v-6h4v6h5v-8h3L12...');
Styling SVGs in React
CSS Styling
/* styles.css */
.icon {
width: 24px;
height: 24px;
fill: currentColor;
transition: fill 0.2s;
}
.icon:hover {
fill: #0066cc;
}
Styled Components
import styled from 'styled-components';
const StyledSvg = styled.svg`
width: ${props => props.size || 24}px;
height: ${props => props.size || 24}px;
fill: ${props => props.color || 'currentColor'};
transition: fill 0.2s;
&:hover {
fill: ${props => props.hoverColor || props.color};
}
`;
Tailwind CSS
<svg
className="w-6 h-6 fill-current text-gray-600 hover:text-blue-500 transition-colors"
viewBox="0 0 24 24"
>
<path d="..."/>
</svg>
Animation in React
CSS Animation
function LoadingSpinner() {
return (
<svg className="animate-spin" viewBox="0 0 24 24">
<circle
className="opacity-25"
cx="12" cy="12" r="10"
stroke="currentColor" strokeWidth="4"
/>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
/>
</svg>
);
}
Framer Motion
import { motion } from 'framer-motion';
function AnimatedIcon() {
return (
<motion.svg
viewBox="0 0 24 24"
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ type: 'spring' }}
>
<motion.path
d="M12 2L2 22h20L12 2z"
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
/>
</motion.svg>
);
}
Free SVG Tools for Crafters
Design Checker · Color Separator · Mat Preview · Offset Generator · Text to SVG
Check Your SVG FreeOptimization Strategies
Build-Time Optimization
// svgo.config.js
module.exports = {
plugins: [
'preset-default',
'removeDimensions',
{ name: 'removeViewBox', active: false },
{ name: 'prefixIds', params: { prefix: 'svg-' } }
]
};
Code Splitting
// Lazy load heavy icons
const ChartIcon = lazy(() => import('./icons/Chart'));
function Dashboard() {
return (
<Suspense fallback={<div className="icon-placeholder" />}>
<ChartIcon />
</Suspense>
);
}
Never remove viewBox during SVGO optimization. Without viewBox, SVGs lose their ability to scale responsively. Always set removeViewBox: false in your SVGO config.
Accessibility in React
Accessible Icon Pattern
interface AccessibleIconProps {
label: string;
children: React.ReactNode;
}
function AccessibleIcon({ label, children }: AccessibleIconProps) {
return (
<span role="img" aria-label={label}>
{children}
</span>
);
}
// Usage
<AccessibleIcon label="Search">
<SearchIcon />
</AccessibleIcon>
Icon Button
function IconButton({ icon: Icon, label, onClick }) {
return (
<button
onClick={onClick}
aria-label={label}
className="icon-button"
>
<Icon aria-hidden="true" />
</button>
);
}
Vectosolve Integration
Workflow
Using Vectosolve with React:
- Convert images to SVG
- Download clean output
- Import into React project
- Use preferred method above
Clean Output Benefits
Vectosolve SVGs are:
- Optimized for web use
- Ready for SVGR import
- Clean path data
- Easy to style
A Full Year of Conversions for $49
Starter Annual: 25 conversions every month, $49 for the whole year. That is about $4.08 a month · Cancel anytime
Get the Annual DealConclusion
React offers multiple ways to work with SVGs, each with trade-offs. Choose the approach that fits your needs: simple image imports for basic use, SVGR for full control, or component patterns for icon systems. Start with clean, optimized SVGs from Vectosolve for the best results.
| SVG Import Method | Runtime Control | Bundle Impact | Best For |
|---|---|---|---|
| <img src> import | None | Separate HTTP request | Static decorative images |
| Inline JSX SVG | Full (props, events, CSS) | Increases component size | Interactive icons, animations |
| SVGR component | Full (typed props, tree-shaking) | Per-component chunk | Icon libraries, design systems |
| Dynamic import | Full (after load) | Code-split, lazy loaded | Below-fold or conditional SVGs |