Introduction

There are plenty of ways to include SVG files in your React apps. One that I was using until recently was to include the SVG with an object tag. While it worked ok, there's a much better way. What if you could include the SVG files directly in the generated markup?

Enter SVGR

SVGR provides a way to generate react components from SVG files that you can easily import in your code. It comes built-in with create-react-app, so if your code is generated from it, you don't need to read further. In fact, the official docs cover the default behavior pretty well and it is easy to set up.

But if you are looking for a solution to generate tsx files from SVG, you are in the right place. From the documentation, svgr has an option to specify a template that you want it to use.

A custom template takes place in a file that exports a "template function".

This function is called in a babel plugin: babel-plugin-transform-svg-component and must returns a Babel AST. If you are not familiar with all Babel stuff, you should read this guide.

Reading the Babel AST guide, we can prepare our template so that it writes out a typescript file instead of vanilla JS.

function defaultTemplate(  
  { template },
  opts,
  { imports, interfaces, componentName, props, jsx, exports },
) {
  const plugins = ['jsx']
  if (opts.typescript) {
    plugins.push('typescript')
  }
  const typeScriptTpl = template.smart({ plugins })
  return typeScriptTpl.ast`${imports}
${interfaces}
function ${componentName}(${props}) {  
  return ${jsx};
}
${exports}
  `
}
module.exports = defaultTemplate  

Now use this template when processing the SVG files:

$ yarn svgr --template template.js play.svg

Here's the output of play.tsx:

import * as React from "react";

function SvgPlay(props) {  
  return (
    <svg baseProfile="tiny" viewBox="0 0 24 34" {...props}>
      <path d="M7 22.2V11.8c0-.8.9-1.2 1.5-.8l8.1 5.2c.6.4.6 1.3 0 1.7L8.5 23c-.6.4-1.5 0-1.5-.8z" />
    </svg>
  );
}

export default SvgPlay;  

Automation

If you are looking to automate the generation of these files so that you don't have to run these commands every time a new SVG file is added, here's how you can do that with Grunt (it's possible with many other tools, including gulp, but our project was using Grunt).

We need to use the grunt-shell task with this config.

svgr: {  
  command: 'yarn svgr --ext tsx --template lib/misc/svgr_template.js -d lib/src/svg lib/svg',
}