Mapping Styles to Compose theme

Mapping from Styles in Figma to Theme in Compose

Figma lets designers apply a style to a design element. A style is a reusable collection of properties, such as colors or typography. Since it is centrally defined, a team can define and update properties across all designs when updating a single design element. You can set up Relay so it translates Figma styles to Jetpack Compose themes.

The mapping between Figma styles and Compose themes is specified through a configuration file.

Configuration file maps Figma styles and Compose themes

As an example, the Figma design shown below uses styles from Google’s Material 3 Design Kit. For the text Primary - Title large, the font is M3/title/large and its color is M3/sys/light/primary..

Material 3 styles in Figma

If we import the design with M3 Design Kit styles translation enabled, the following code is generated for the Primary - Title large text:

@Composable
fun PrimaryTitleLarge(modifier: Modifier = Modifier) {
    Text(
        content = "Primary - Title large",
        fontSize = MaterialTheme.typography.titleLarge.fontSize,
        fontFamily = MaterialTheme.typography.titleLarge.fontFamily,
        color = MaterialTheme.colorScheme.primary,
        height = MaterialTheme.typography.titleLarge.lineHeight,
        letterSpacing = MaterialTheme.typography.titleLarge.letterSpacing,
        textAlign = TextAlign.Left,
        fontWeight = MaterialTheme.typography.titleLarge.fontWeight,
        modifier = modifier
    )
}

To use this feature, use styles as you normally would in Figma. Then in Android Studio, go to the File > New > Import UI Packages…, and then check Translate Figma styles to Compose theme.

At this point, you must choose a configuration for translating your design’s styles:

  • If they directly come from Google’s Material 3 Design Kit for Figma (which have the format M3/body/medium or M3/sys/light/primary), then select the Material 3 Design Kit configuration option.
  • If they directly come from Google’s Material 2 Design Kit for Figma (which have the format 01. Primary/500 or Subtitle 1), then select the Material 2 Design Kit configuration option.
  • If you have your own style definitions, then select the Custom configuration option and choose the file that contains the mappings between Figma styles and Compose themes (described in this section).

    Import UI Package dialog

If there are styles in the Figma design that are not in the selected configuration, the Import dialog shows a warning for each unmapped style. Each unmapped style is translated to its literal value instead. The warnings are initially collapsed; click on the warnings banner to expand. Each warning has a link to the specific layer in the Figma file that causes the warning.

Warnings in the import dialog

After importing, the style configuration are located in the Android Studio project. Look for them inside the ui-package-resources/style-mappings directory.

Configuration files for custom translations

Translating Figma styles to Compose themes consists of two steps:

  1. A Figma style in a UI Package is translated to a design token in the UI Package definition JSON file, within the UI Package folder in your Android Studio project.
  2. A design token in a UI Package definition file is translated to a snippet of Compose theme code in your Android Studio project.

The format of the custom configuration file (which is in JSON format) reflects these two steps. Here is an example of a simple custom configuration file that only handles color styles:

{
  "figma": {
    "colors": {
      "my-app-theme/sys/light/primary": "myapp.sys.color.primary",
      "my-app-theme/sys/light/primary-container": "myapp.sys.color.primary-container",
      "my-app-theme/sys/light/background": "myapp.sys.color.background",
      "my-app-theme/sys/light/on-background": "myapp.sys.color.on-background",
      "my-app-theme/sys/dark/background": "myapp.sys.color.background",
      "my-app-theme/sys/dark/on-background": "myapp.sys.color.on-background"
    }
  },
  "compose": {
    "colors": {
      "myapp.sys.color.primary": "MaterialTheme.colorScheme.primary",
      "myapp.sys.color.primary-container": "MaterialTheme.colorScheme.primaryContainer",
      "myapp.sys.color.background": "MaterialTheme.colorScheme.background",
      "myapp.sys.color.on-background": "MaterialTheme.colorScheme.onBackground"
    },
    "options": {
      "packages": {
        "MaterialTheme": "androidx.compose.material3"
      }
    }
  }
}

There are two top-level sections, figma (which specifies step 1) and compose (which specifies step 2). Both of them include a colors section:

  • figma’s colors section specifies a Figma style and the corresponding design token that should be written to the UI Package definition file.
  • compose’s colors section specifies a design token in the UI Package definition file and the corresponding code snippet that should be written to your Compose code.

In the example configuration above, anything using the color my-app-theme/sys/light/primary in Figma has its color written as myapp.sys.color.primary in the UI Package definition file. Then, during code generation, that color is written as MaterialTheme.colorScheme.primary in Compose.

The compose section also contains an options section, which states which package a particular code symbol is in. The example above states that MaterialTheme is in the androidx.compose.material3 package, which therefore should be imported in any generated code.

Mapping typography styles is a little more involved than color styles. Here is the same example as above, but with typography styles added:

{
  "figma": {
    "colors": {
      "my-app-theme/sys/light/primary": "myapp.sys.color.primary",
      "my-app-theme/sys/light/primary-container": "myapp.sys.color.primary-container",
      "my-app-theme/sys/light/background": "myapp.sys.color.background",
      "my-app-theme/sys/light/on-background": "myapp.sys.color.on-background",
      "my-app-theme/sys/dark/background": "myapp.sys.color.background",
      "my-app-theme/sys/dark/on-background": "myapp.sys.color.on-background"
    },
    "typography": {
      "symbols": {
        "my-app-theme/headline/large": "myapp.sys.typescale.headline-large",
        "my-app-theme/body/medium": "myapp.sys.typescale.body-medium"
      },
      "subproperties": {
        "fontFamily": "font",
        "fontWeight": "weight",
        "fontSize": "size",
        "letterSpacing": "tracking",
        "lineHeightPx": "line-height"
      }
    }
  },
  "compose": {
    "colors": {
      "myapp.sys.color.primary": "MaterialTheme.colorScheme.primary",
      "myapp.sys.color.primary-container": "MaterialTheme.colorScheme.primaryContainer",
      "myapp.sys.color.background": "MaterialTheme.colorScheme.background",
      "myapp.sys.color.on-background": "MaterialTheme.colorScheme.onBackground"
    },
    "typography": {
      "symbols": {
        "myapp.sys.typescale.headline-large": "MaterialTheme.typography.headlineLarge",
        "myapp.sys.typescale.body-medium": "MaterialTheme.typography.bodyMedium"
      },
      "subproperties": {
        "font": "fontFamily",
        "weight": "fontWeight",
        "size": "fontSize",
        "tracking": "letterSpacing",
        "line-height": "lineHeight"
      }
    },
    "options": {
      "packages": {
        "MaterialTheme": "androidx.compose.material3"
      }
    }
  }
}

The typography sections’ structure reflects the fact that a typography style is made up of many sub-properties. In Figma and Compose, a typography style includes the typeface’s name, font weight, size, letter spacing, and line height, among many others. Instead of needing to map each style’s individual sub-properties over and over again, we instead map the overall styles to tokens and themes, and then separately map each individual sub-property.

The example above states that when a Figma text item with the style my-app-theme/headline/large is written to the UI Package definition file, the text’s font is myapp.sys.typescale.headline-large.font, its size is myapp.sys.typescale.headline-large.size, and so on. Then, when Compose code is generated, a RelayText composable (which wraps the Text composable in Compose Material) is created, where the font parameter is MaterialTheme.typography.headlineLarge.fontFamily, the size parameter is MaterialTheme.typography.headlineLarge.fontSize, and so on.

For examples of configuration files, you can look at the built-in Material 3 and Material 2 Design Kit configurations, which use exactly the same format. You can download the files here:

Limitations

Currently, there are several situations where styles are not translated to themes:

  • Text styles that are applied to only a part of a text element (as described in Multiple styles in text)
  • If there are different styles applied to different variants of a component, only one style is translated.