Generating TypeScript React components from SVG icons using SVGR
SVGR is a tool that converts SVG files into React components. It supports TypeScript generation. However, it only supports default exports. To generate components with named exports we need to use a custom template.
- Install all the dependencies:
npm install --save-dev @svgr/core @svgr/plugin-svgo @svgr/plugin-prettier glob
- Create a Node.js script, scripts/generate-icons.js:
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const svgr = require('@svgr/core').default;
const ICONS_SOURCE_DIR = 'assets/icons';
const COMPONENTS_DIR = 'src/Icons2';
// Template to generate named exports instead of default ones
const iconComponentTemplate = (
{ template },
opts,
{ imports, componentName, jsx }
) =>
template.smart({ plugins: ['typescript'] }).ast`
${imports}
${'\n'}
export const ${componentName} = (props: React.SVGProps<SVGSVGElement>) => ${jsx};
`;
const icons = glob.sync(`${ICONS_SOURCE_DIR}/**.svg`);
for (const icon of icons) {
const svg = fs.readFileSync(icon, 'utf8');
const componentName = path.parse(icon).name;
const componentCode = svgr.sync(
svg,
{
template: iconComponentTemplate,
// 1. Clean SVG files using SVGO
// 2. Generate JSX
// 3. Format the result using Prettier
plugins: [
'@svgr/plugin-svgo',
'@svgr/plugin-jsx',
'@svgr/plugin-prettier'
],
// Replace hardcoded colors with `currentColor`
svgoConfig: {
plugins: [{ convertColors: { currentColor: true } }]
},
// Replace dimensions
svgProps: { height: 32, width: 32, viewBox: '0 0 32 32' }
},
{ componentName }
);
fs.writeFileSync(
`${COMPONENTS_DIR}/${componentName}.tsx`,
componentCode
);
}
- Run the script:
node scripts/generate-icons.js
The resulting TypeScript component files should look like this:
import * as React from 'react';
export const Unsplash = (props: React.SVGProps<SVGSVGElement>) => (
<svg viewBox="0 0 32 32" height={32} width={32} {...props}>
<path
d="M20.8 18.1c0 2.7-2.2 4.8-4.8 4.8s-4.8-2.1-4.8-4.8c0-2.7 2.2-4.8 4.8-4.8 2.7.1 4.8 2.2 4.8 4.8zM32 10.7v14.9c0 2.3-1.9 4.3-4.3 4.3H4.3C1.9 29.9 0 28 0 25.6v-15c0-2.3 1.9-4.3 4.3-4.3H8L8.8 4c.4-1.1 1.7-2 2.9-2h8.6c1.2 0 2.5.9 2.9 2l.8 2.4h3.7c2.4 0 4.3 1.9 4.3 4.3zm-8.6 7.5c0-4.1-3.3-7.5-7.5-7.5-4.1 0-7.5 3.4-7.5 7.5s3.3 7.5 7.5 7.5c4.2-.1 7.5-3.4 7.5-7.5z"
color="currentColor"
/>
</svg>
);
And we can use it like this:
<Unsplash />
Based on codesandbox-client, thanks to Sid.