Developers can customize the code generation process by providing a mapping between a UI Package and an existing code component instead of the generated code. This is beneficial when the existing implementation has features that cannot be achieved by the generated code such as animation or complex behavior (such as a drop down menu).
Developers specify how to map components using a mapping file. A mapping file tells the code generator, at minimum, how to reach the desired composable function so that the right client code can be created.

Here is an example:
In Figma, a designer creates a Card component that contains an instance of a Play Bar component, packages both components, and sends them to a developer.
When the developer imports the UI packages from Figma, two directories are
created in ui-packages
: card
and play_bar
. When they build the project,
two composable functions are created: Card
and PlayBar
. Typically, because
Card contains a Play Bar instance in Figma, in code the Card
composable function contains a call to the PlayBar
composable.
However, the designer and developer want Card
to instead use an existing
composable, MyExistingPlaybar
, which has functionality that is hard to
describe in Figma. So the developer adds a mapping file called play_bar.map
that maps the play_bar
UI package to MyExistingPlaybar
:
{
"target": "MyExistingPlaybar",
"package": "com.example.myApp"
}
Now, when the developer builds the project, Card
calls MyExistingPlaybar
instead of PlayBar
. Note that MyExistingPlaybar
must have the same
parameters as PlayBar
(although there can be a few differences, as described
in Additional Directives below).
Mapping file
In your Android Studio projects, mapping files are added under
ui-package-resources/mappings
next to the ui-packages
folder. Relay will
look for your mapping files during build.

Mapping file name
The name of a given mapping file must match the name of the UI Package folder
for the component it replaces. So play_bar.map
maps the UI Package in the
ui-packages/play_bar
folder to an existing code component.
Mapping file contents
The mapping file contains the following properties:
target : (Required) The name of your custom composable function. By default, this is the name of the function created by generated code.
"target" : "CustomComposableName"
package : (Required) Name of the package that your custom composable sits in. By default, this is the package of the function created by generated code.
"package" : "com.example.podcastapp.ui.components"
generateImplementation : (Optional) true or false. If true, an implementation of this UI package is still created in the generated code file. If false, the implementation isn't created. By default, this is true.
"generateImplementation" : true
generatePreviews : (Optional) true or false. If true, a preview of the mapped custom component is created in the generated code file. If false, no preview is created. By default, this is true.
"generatePreviews" : true
Mapped variants
If a Figma component has variants, then the generated composable will have enum
parameters that encode the variant (as described in the Handling Design
Variants tutorial). If you want to map a Figma component with variants to
existing code, it needs to be mapped to a composable that takes the same
parameters as the generated composable, except that the enum parameter is
replaced by a string parameter called design
. For example, suppose there is a
Figma component called Chip with a variant whose property is ChipType.
Chip’s generated composable signature looks like this:
@Composable
fun Chip(
modifier: Modifier = Modifier,
chipType: ChipType = ChipType.Red,
chipText: String
) { ... }
If you want to have the Chip Figma component map to an existing MyChip
composable, then the signature for MyChip
must have the same signature as the
generated composable (assuming no additional directives are specified).
Conceptually, this suggests that the existing code component is capable of the
same design variants as the Figma component.
Additional directives
Suppose the composable function we want to target has the following signature:
@Composable
fun MyChip(
modifier: Modifier = Modifier,
chipType: ChipType = ChipType.Red,
description: String // instead of chipText
) { ... }
We can add a fieldMappings
block to the mapping file that affects how
parameters are mapped. In this case, it contains a mapping from the chipText
parameter in the Chip
to the description
parameter in MyChip
.
{
"target": "MyChip",
"package": "com.example.myApp",
"fieldMappings": [
{
"type": "parameter",
"source": "chipText",
"target": "description"
}
]
}
The types for the fieldMappings
block include:
type: parameter
maps a UI package field to a code parameter.source
: Name of parameter as specified in the UI package.target
: Name of parameter as specified in the target code component.
type: lambda
maps a UI package field to a content lambda.source
: Name of parameter as specified in the UI package.target
: Name of parameter as specified in the target code component.
type: modifier
maps a UI package field to a modifier method. Note: This mapping type is being incubated, in particular the handling of receiver scopes.source
: Name of parameter as specified in the UI package.method
: Method on the Modifier object that should be invoked in generated code.parameter
: Name of parameter within the specified Modifier method.library
: The qualified package name to import to access the Modifier method.scope
: One of two values to indicate the scope of the Modifier:any
: The modifier can be used in any receiver scope.relay
: The modifier must be used in the receiver scope of Relay’sRelayContainer
object.