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.
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..
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).
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.
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:
- 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.
- 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
’scolors
section specifies a Figma style and the corresponding design token that should be written to the UI Package definition file.compose
’scolors
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.
Recommended for you
- Note: link text is displayed when JavaScript is off
- Other considerations
- Kotlin for Jetpack Compose
- Locally scoped data with CompositionLocal