From Figma to React Native using Specify
Tags: design, reactnative, figma
Published: 2022-03-11 14:20:19

 > This post originally appeared on our [ITP Dev blog](https://inthepocket.dev/posts/2021-10-14-figma-to-react-native/)

We all know the benefit of **design systems**. As a designer we want to have a consistent UI over web, mobile and any other platform the brand is present. As a developer we do not want to spend time exporting assets and colors from Figma, importing them into the code and repeating this process every time something changes.

Luckily there exists a tool to automate this process. [Specify](https://specifyapp.com) is a cloud platform which stores a **single source of truth** for your design tokens (text styles, colors, icons, imagery, etc.) and distributes them to the different platforms. Specify allows you to **import** your tokens from a source like Figma (and soon other sources like Google Drive or Dropbox) and keep them in sync while you make changes to the source. You can view the tokens in the web app and export them to GitHub or to your project using the [CLI](https://specifyapp.com/developers/cli).

In this blogpost we will focus on syncing the design tokens from Figma to React Native.

## Figma to Specify


![Screenshot of the Specify dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/veyeqikgcdzyi3a8ahrz.png)

Syncing design tokens from Figma to Specify is just a matter of clicking a few buttons. The Specify team has written a clear [guide](https://help.specifyapp.com/en/articles/4722449-figma-integration) on how to set it up, and Specify will automatically sync any new changes made to the Figma file.
I recommend taking a look at the [example Figma file](https://www.figma.com/file/ilwc27dKXPt3QTGORsVZwl/Specify-%C2%B7-File-Example?node-id=0%3A1&viewport=25%2C361%2C0.3232876658439636) to see how each design token should be delivered.

## Specify to React Native


![Illustration of a flow going from the Specify logo to the React Native Logo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y1rjuko46h328ie1uiti.png)

To pull design tokens into a project, Specify offers a [CLI](https://specifyapp.com/developers/cli) with a `pull` and `sync` command. The `pull` command will import all design tokens, where the `sync` command will only update the ones that are already present.
The CLI uses a `.specifyrc` config file (JS or JSON) in which you can write **rules**, which are different jobs to run in parallel.

```js
// .specifyrc.js
module.exports = {
  repository: '@my_organization/my-repository',
  personalAccessToken: 'my_personal_access_token',
  rules: [
    // different jobs in parallel
  ],
};
```

For each rule we can use a different **filter**, such that the rule only applies to certain types of design tokens. Next to filters, we can also use **parsers**, which will manipulate the raw design tokens (which are in JSON format) and output a format that suits the programming language and platform more. Parsers behave like a pipeline, where each parser receives the input of the previous one. There are a lot of [parsers](https://github.com/Specifyapp/parsers/tree/master/parsers) to choose from, some perform very low level transformations such as [round-number](https://github.com/Specifyapp/parsers/tree/master/parsers/round-number) and [camelcasify](https://github.com/Specifyapp/parsers/tree/master/parsers/camelcasify), but also full-blown parsers to a single technology such as [to-tailwind](https://github.com/Specifyapp/parsers/tree/master/parsers/to-tailwind) and [to-react-native](https://github.com/Specifyapp/parsers/tree/master/parsers/to-react-native).

### Downloading fonts & assets

If we filter on assets (`'vector'`, `'bitmap'` and `'font'`), Specify will download the assets themselves instead of the JSON describing them. They will be placed under the given folder (here `src/common/assets`).

For SVG's, we can use the [`svgo`](https://github.com/svg/svgo) parser, which optimizes the SVG code and outputs a minified result. The default `svgo` settings are pretty good, but we add `removeDimensions` to make them responsive and replace the hard coded colors with `"currentColor"` such that we can color them with React Native styles.

```js
// .specifyrc.js
  ...
  rules: [
    {
      name: "🖊 Download Vector Assets",
      path: "src/common/assets/vector",
      filter: {
        types: ["vector"],
      },
      parsers: [
        { name: "camelcasify" },
        {
          name: "svgo",
          options: {
            svgo: {
              plugins: [
                { removeDimensions: true },
                { convertColors: { currentColor: true } },
              ],
            },
          },
        },
      ],
    },
    {
      name: "🏞 Download Bitmap Assets",
      path: "src/common/assets/bitmap",
      filter: { types: ["bitmap"] },
      parsers: [
        { name: 'camelcasify' },
        {
          // This parser will give @2x and @3x variants their correct file name
          name: 'name-assets-files-by-pattern',
          options: {
            pattern: '{{name}}{{#dimension}}@{{dimension}}x{{/dimension}}.{{format}}',
          },
        },
      ],
    },
    {
      name: "🔡 Download Fonts",
      path: "src/common/assets/fonts",
      filter: { types: ["font"] },
    },
  ],
  ...
```

### Syncing desing tokens

Now that assets and fonts are downloaded, we are ready to import the rest of the design system. For this we will use the [`to-react-native`](https://github.com/Specifyapp/parsers/tree/master/parsers/to-react-native) parser. It will generate a JavaScript (or TypeScript) `theme` object with all the design tokens in the correct format for React Native to understand.

```js
// .specifyrc.js
...
{
  name: '⚛️ Import tokens',
  path: 'src/common/theme/theme.js',
  parsers: [
    {
      name: 'to-react-native',
      options: {
        assetsFolderPath: {
          bitmap: 'src/common/assets/bitmap',
          vector: 'src/common/assets/vector',
        },
      },
    },
  ],
},
...
```

> If you have questions or notice any issues with the `to-react-native` parser, feel free to [contribute](https://github.com/Specifyapp/parsers) or talk to me about it 🙏

An example of a full `.specifyrc.js` file can be found [here](https://gist.github.com/robrechtme/453f3c3e5ddf1e222417ae3e99faedcd). The output file will look something like this:

```js
// src/common/theme/theme.js
import assetChevronRight from '../assets/vector/chevronRight.svg';
import assetLogo from '../assets/bitmap/logo.png';

const theme = {
  bitmap: {
    logo: assetLogo,
  },
  vector: {
    chevronRight: assetChevronRight,
  },
  textStyle: {
    body: {
      fontWeight: '500',
      fontSize: 16,
      lineHeight: 24,
      fontFamily: 'Montserrat-Medium',
      color: 'rgb(0, 0, 0)',
    },
  },
  measurement: {
    grid: 8,
  },
  color: {
    primary500: 'rgb(0, 0, 153)',
  },
  gradient: {
    sunset: [
      {
        angle: 90,
        colors: ['rgb(245, 72, 63)', 'rgb(255, 142, 5)'],
        locations: [0, 1],
      },
    ],
  },
  opacity: {
    dimmed: 0.6,
  },
  font: {
    montserratMedium: 'Montserrat-Medium',
  },
};

export default theme;
```

As a final step we will add an npm script in our `package.json`:

```json
// package.json
  "scripts": {
    ...
    "specify:pull": "specify pull -C .specifyrc.js",
  },
```

Now we have our Figma project synced with React Native 🎉. Every time the designer changes a color or adds an icon, we can run `npm run specify:pull` and see the changes in our app!

### Using the theme object

Making use of the design tokens is fairly straighforward for most types.

#### Bitmaps

Simple as that!

```tsx
import { Image } from 'react-native';
import theme from 'common/theme';

const App = () => <Image source={theme.bitmap.logo} />;
```

#### Vectors

All vector assets in `theme.js` are imported directly. If you are not using Expo, you will need to install and configure [`react-native-svg-transformer`](https://github.com/kristerkari/react-native-svg-transformer) to resolve the import statements.

Unlike bitmaps, the imported assets are React elements. We create a `Vector` component to make the usage look more like regular images:

```tsx
const Vector = ({ source: SVGElement, ...props }) => <SVGElement {...props} />;

const App = () => (
  <>
    {/* a bit weird */}
    <theme.vector.chevronRight />
    {/* much better! */}
    <Vector source={theme.vector.chevronRight} />
  </>
);
```

### Fonts

> This part is specific to non-Expo projects. For Expo apps, it could be different.

In the "Download Fonts" rule above, the downloaded `.ttf` files will be under `src/common/assets/fonts/`, but they should also be imported in the native projects as well. This can be done by creating a `react-native.config.js`

```js
// react-native.config.js
module.exports = {
  project: {
    ios: {},
    android: {},
  },
  assets: ['src/common/assets/fonts/'],
  dependencies: {
    // Optionally.
    // Prevent `react-native-vector-icons`
    // from linking all fonts
    'react-native-vector-icons': {
      assets: [],
    },
  },
};
```

Running `react-native link` will link all fonts under that path automatically to the Android and iOS project! We can run it after every specify pull job:

```diff
// package.json
  "scripts": {
    ...
-    "specify:pull": "specify pull -C .specifyrc.js",
+    "specify:pull": "specify pull -C .specifyrc.js && react-native link",
  },
```

#### Gradients

The `to-react-native` parser transforms gradients into a format which is easy to use with [react-native-linear-gradient](https://github.com/react-native-linear-gradient/react-native-linear-gradient).
Example usage:

```tsx
const App = () => (
  <LinearGradient
    colors={theme.gradients.myGradient.colors}
    locations={theme.gradients.myGradient.locations}
    useAngle
    angle={theme.gradients.myGradient.angle}
  />
);
```

## Conclusion

Specify is a young but promising tool to sync Figma files to all you different platforms. If you feel like there is a parser missing or want to add some options, feel free to [contribute](https://github.com/Specifyapp/parsers) to the project. The Specify team is very responsive and is open to suggestions.