Export SVGs from Figma for React Native
Tags: react, reactnative, design
Published: 2020-07-29 06:17:58

> This post is focused on React Native, but should be applicable to pretty much anything with little adjustment.

If you have your UI designed in Figma (or any other vector graphics tool), you likely want to export all the assets for your app from there. So here's what you do to get SVGs out ASAP.
**In this particular example I want to export all my icons as SVGs**

## Export SVGs from Figma

- Make sure your shapes do not use stroke. To get rid of it:
  - try using “outline stroke” and then merging with original shape.
- Make sure all shapes are flat (flatten all groups)
- Give all your shapes meaningful and unique names
- Make all shapes black `#000`
- Export SVGs using “Advanced SVG Export” plugin:
  - Select all shapes you want to export and then open "Advanced SVG Export" plugin
  - Make sure you selected “Prefer viewBox to width/height” in plugin settings 
  - Click on "export layers"
  - Extract downloaded archive into `assets/icons` directory of your project

## Generate React Component For Each SVG

I use TypeScript, so following generates `app/components/icons/index.tsx` file with component per each SVG.

- Install hygen - [follow docs](https://www.npmjs.com/package/hygen)
- Run `hygen generator new icons`
- Change `_templates/icons/new/hello.ejs.t` to:
```js

---
to: app/components/icons/index.tsx
---

/**********************************************
 *    THIS IS AUTOGENERATED CODE              *
 *    GENERATOR: hygen icons new              *
 **********************************************/

<% 
  const dir = './assets/icons';
  const fs = h.require('fs');

  const files = fs.readdirSync(dir)
%>

<%- 
  files.map(v => `import ${v.split('.')[0]}SVG from "../../../assets/icons/${v}"`).join('\n')
%>

import {CreateIcon} from './createIcon';

<%- 
  files.map(v => `export const ${v.split('.')[0]}Icon = CreateIcon(${v.split('.')[0]}SVG)`).join('\n')
%>

```
It's nice to have `CreateIcon` function in separate file, so you can edit it without touching template. Here's what `createIcon.tsx` may look like:

```tsx
import React from 'react';
import {View} from 'react-native';
import {SvgProps} from 'react-native-svg';

export interface IconProps {
  containerStyle?: object;
  color: string;
  size: number;
}

export function CreateIcon(Icon: React.FC<SvgProps>) {
  return ({color, size, containerStyle}: IconProps) => {
    return (
      <View
        style={[
          {
            width: size,
            height: size,
            justifyContent: 'center',
            alignItems: 'center',
          },
          containerStyle,
        ]}>
        <Icon fill={color} width={size} height={size} />
      </View>
    );
  };
}
```

- Add `"g:icons": "HYGEN_OVERWRITE=1 hygen icons new"`, to `"scripts"` in `package.json`

With above setup you extract all your svgs into `assets/icons`, then run `yarn g:icons` (or `npm run g:icons`) which will generate `app/components/icons/index.tsx` with one component per each SVG file. Yay!

## RN Setup

- Install following npm packages: `react-native-svg`, `@svgr/core`, `@svgr/plugin-svgo`, `react-native-svg-transformer`, `svgo`
- Create `.svgrrc` file in the project root directory with following content: 
```json
{
  "replaceAttrValues": {
    "#000": "{props.color}"
  }
}
```
- Adjust `metro.config.js` as following:
```js
const {getDefaultConfig} = require('metro-config');

module.exports = (async () => {
  const {
    resolver: {sourceExts, assetExts},
  } = await getDefaultConfig();
  return {
    transformer: {
      babelTransformerPath: require.resolve('react-native-svg-transformer'),
      getTransformOptions: async () => ({
        transform: {
          experimentalImportSupport: false,
          inlineRequires: false,
        },
      }),
    },
    resolver: {
      assetExts: assetExts.filter((ext) => ext !== 'svg'),
      sourceExts: [...sourceExts, 'svg'],
    },
  };
})();
```
   + If you use Typescript, create/edit `@types/declarations.d.ts`:

     ```ts
     declare module '*.svg' {
       import {SvgProps} from 'react-native-svg';
       const content: React.FC<SvgProps>;
       export default content;
     }
     ```

## That's It!

Hope that was helpful!
Any questions / suggestions are welcome :)