SVG icons in React: components that scale and recolor
An icon in a React app is best as a component: it takes a size and a color like any other element, ships with the code, and needs no extra request. Here is the pattern and the tools that produce it.
The component
import type { SVGProps } from "react";
export function RocketIcon({ size = 24, title, ...props }: SVGProps<SVGSVGElement> & { size?: number; title?: string }) {
return (
<svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" role={title ? "img" : undefined} aria-hidden={title ? undefined : true} {...props}>
{title ? <title>{title}</title> : null}
<path d="…" />
</svg>
);
}Use it as <RocketIcon size={20} className="text-emerald-600" />. The SVG to React tool writes this file from any SVG, in TypeScript or JavaScript, and a ZIP of many icons comes with an index file.
Color
One-color icons should use currentColor so they follow the surrounding text color; the converter does this automatically. Multi-color icons keep their fills; pass a className to adjust opacity or size instead.
Accessibility
Decorative icons (next to a label) get aria-hidden. Icons that carry meaning on their own (an icon-only button) get a title, which the component turns into role="img". For buttons, an aria-label on the button is the simplest option.
Bundle size
Import icons one by one from an icons folder, not from a barrel file that re-exports hundreds; tree shaking then drops the unused ones. Optimize the SVGs before converting (the SVG optimizer removes editor metadata and rounds coordinates), which often halves the component.
| Set size | Approach |
|---|---|
| Up to ~50 icons | Components, imported individually |
| Hundreds | A sprite file with use, or lazy-loaded groups |
| User-uploaded | img tag pointing at the file |
Vue, Svelte and React Native
The same pattern applies elsewhere, and IconHub has a converter for each: SVG to Vue (single-file component with a size prop), SVG to Svelte (size prop and $$restProps) and SVG to React Native (react-native-svg elements with a color prop).
Tip: Next.js and Vite need no plugin for these components; they are plain JSX. If you prefer importing .svg files directly, SVGR does the same transformation at build time.