Nested package instances

A UI Package with nested
instances

UI Packages can contain (or "nest") instances of other UI Packages, with support for dynamic content and interactivity at each level—all automatically imported using the Relay for Android Studio plugin.

Add nested instances and expose nested parameters

Package instances can be added as you would normally add component instances in Figma.

Once you add a nested package instance to a package, you can add content and interaction parameters based on the nested instance parameters, just like the properties of any other layer:

  • Select the packaged instance layer.
  • Click the + add parameter in the Relay for Figma UI.
  • Select one of the nested package parameters.

The selected parameter or interaction is exposed by the parent component, forming a connection between the nested package parameter and a new parameter added to the parent component. In the generated code, you can now provide a value to the parent, which is passed through to an instance of the nested package's code component.

If the nested instance is present in multiple Figma variants in the parent component, the UI groups variant instances to enable individual configuration.

Grouping instances per
variant

By default, nested package instance parameters are not exposed by the parent component. Instead, the generated code uses the value you specify in Figma, just like regular parameter overrides.

Exposing nested instance parameters by their
parents

Let's look at this example:

  • The Chip package has one text parameter, chip-text.
  • The Description Card package contains a Chip package. Its parameters are:
    • title
    • subchip-text, which exposes the Chip instance's chip-text parameter
    • sub-icon
    • details
  • The Reservation Card package contains a Description Card package. Its parameters are:

    • hero-image
    • headline, which exposes the Description Card instance's title parameter.

    • reservation-text, which exposes the Description Card instance's chip-text parameter.

    • summary, which exposes the Description Card instance's details parameter.

Note that sub-icon is the only parameter of the Description Card that is not exposed by the Reservation Card. Therefore, every instance of a Reservation Card uses the icon that the Description Card provides by default.

To expose a parameter of a nested component instance:

  1. Select a nested instance of a UI Package that has parameters. You can select the instance in the canvas directly or in the Relay for Figma plugin under Relay instances.
  2. Click + next to Parameters. The menu shows the parameters from the selected instance. Select a parameter.

    This exposes a parameter from the nested instance. In this example, we've selected the Description Card instance and exposed the details parameter.

    Exposing the details parameter of Description
Card

  3. In the pane on the right side of the Relay for Figma plugin, you can select a different parameter, or rename the parameter to change how it is called in the generated code. In this example, the parameter is renamed to summary, which still refers to the details parameter from our nested instance.

    Renaming the details parameter to
summary

When you import a parent component (in this case, Reservation Card) into Android Studio, all nested packages are automatically imported (in this case, Description Card and Chip). When the code is generated, each package generates its own composable function.

UI Packages and generated
code

The generated code for the example looks like:

ReservationCard.kt

..
import com.example.hellofigma.descriptioncard.DescriptionCard
...

@Composable
fun ReservationCard(
    modifier: Modifier = Modifier,
    heroImage: Painter,
    headline: String,
    summary: String,
    reservationText: String
) {
    ...
    DescriptionCard(
        title = headline,
        details = summary,
        subchipText = reservationText,
        subIcon = painterResource(R.drawable.reservation_card_bookmark_icon),
        modifier = modifier
    )
    ...
}

DescriptionCard.kt

...
import com.example.hellofigma.chip.Chip
...
@Composable
fun DescriptionCard(
    modifier: Modifier = Modifier,
    title: String,
    details: String,
    subchipText: String,
    subIcon: Painter
) {
   ...
   Chip(chipText = subchipText)
   ...
}

Override properties of nested package instance

If you override the value of a nested instance property in Figma, the new value is only translated in Compose code if the nested component has added a parameter for that property. Otherwise, the new value is dropped, and the original value in the nested component is used in code.

Let's take this example. The Description Card component has a Chip component instance. We've added an override to the Chip instance by changing the text from "Chip Text" to "Reservation Required":

Chip component instance in the Description
Card

If Chip does not have a parameter for its text, then in generated code, the Description Card's chip still says "Chip Text", not "Reservation Required."

@Composable
fun DescriptionCard(
    modifier: Modifier = Modifier,
) {
    ...
    Chip(
        modifier = modifier
        // No parameter available to override the chip's text
    )
    ...
}

@Composable
fun Chip(
    modifier: Modifier = Modifier,
) {...}

If Chip does have a parameter for its text, say, chip-text, then in generated code, DescriptionCard calls Chip with "Reservation Required" as the value of the chipText parameter:

@Composable
fun DescriptionCard(
    modifier: Modifier = Modifier,
) {
    ...
    Chip(
        modifier = modifier,
        chipText = "Reservation Required"
    )
    ...
}

@Composable
fun Chip(
    modifier: Modifier = Modifier,
    chipText: String
) {...}

If Description Card exposes Chip's chip-text parameter as subchip-text, then in generated code, DescriptionCard has a subchipText parameter and calls Chip with subchipText as the value of the chipText parameter:

@Composable
fun DescriptionCard(
    modifier: Modifier = Modifier,
    subchipText: String
) {
    ...
    Chip(
        modifier = modifier,
        chipText = subchipText
    )
    ...
}

@Composable
fun Chip(
    modifier: Modifier = Modifier,
    chipText: String
) {...}

Furthermore, now that "Reservation Required" is the value of a parameter, it shows up in generated code only in the preview of DescriptionCard.

@Preview
@Composable
private fun DescriptionCardPreview() {
    MaterialTheme {
        RelayContainer {
            DescriptionCard(
                subchipText = "Reservation Required",
                modifier = Modifier.rowWeight(1.0f).columnWeight(1.0f)
            )
        }
    }
}

Limitations