Interview QuestionPractical QuestionFollow-up Questions

CompositionLocal in Jetpack Compose

skydovesJaewoong Eum (skydoves)||7 min read

CompositionLocal in Jetpack Compose

CompositionLocal is a mechanism in Jetpack Compose for passing data implicitly down the composition tree without threading it through every composable function as a parameter. It provides scoped access to values like themes, configurations, and platform dependencies that many composables need but few should explicitly accept. By the end of this lesson, you will be able to:

  • Explain how CompositionLocal propagates values through the composition tree.
  • Distinguish between compositionLocalOf and staticCompositionLocalOf.
  • Provide and consume CompositionLocal values correctly.
  • Identify when CompositionLocal is appropriate and when direct parameters are better.

Defining a CompositionLocal

You create a CompositionLocal using either compositionLocalOf or staticCompositionLocalOf. Both require a default value factory that is used when no provider is found in the composition tree:

val LocalUserName = compositionLocalOf { "Guest" }

The naming convention uses the Local prefix to signal that the value is provided through the composition tree rather than passed as a parameter. The default value is returned when a composable reads the CompositionLocal but no ancestor has provided a value through CompositionLocalProvider.

Providing Values

Use CompositionLocalProvider to supply a value within a specific scope. Any descendant composable within that scope can read the provided value:

@Composable
fun GreetingScreen() {
    CompositionLocalProvider(
        LocalUserName provides "skydoves"
    ) {
        UserGreeting()
    }
}

@Composable
fun UserGreeting() {
    val userName = LocalUserName.current
    Text("Hello, $userName!")
}

UserGreeting reads LocalUserName.current without receiving it as a parameter. If GreetingScreen did not provide a value, the default "Guest" from the definition would be used instead.

Values provided through CompositionLocalProvider are scoped to the composable subtree defined by the trailing lambda. Outside that scope, the previous value (or the default) applies. This scoping mechanism allows different parts of the tree to see different values for the same CompositionLocal.

compositionLocalOf vs. staticCompositionLocalOf

The two factory functions differ in how they handle recomposition when the provided value changes:

  • compositionLocalOf: Tracks which composables read the value. When the provided value changes, only the composables that actually called .current recompose. This is efficient when the value changes occasionally and only a few composables consume it.

This interview continues for subscribers

Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.

Become a Sponsor