Jetpack Compose: Have you used CompositionLocal?

I came across this during a project, and once you understand it, it can make your Compose UI much cleaner. ⭐

Think of CompositionLocal as a way to make context-specific data available to composables deeper in the UI tree without passing it through every function parameter.

It can help avoid prop drilling.

🔹 The problem

Imagine you have:

Screen()
    → Header()
        → Profile()
            → UserSettings()

If UserSettings needs some configuration, you could pass it through every composable:

Screen(settings)
Header(settings)
Profile(settings)
UserSettings(settings)

This becomes annoying as the UI grows.

🔹 Enter CompositionLocal

First, define your data:

data class UserSettings(
    val darkMode: Boolean
)

Then create a CompositionLocal:

val LocalUserSettings = compositionLocalOf {
    UserSettings(darkMode = false)
}

Provide the value at the appropriate point in your UI tree:

CompositionLocalProvider(
    LocalUserSettings provides UserSettings(darkMode = true)
) {
    AppContent()
}

Now any composable inside that subtree can access it:

@Composable
fun ProfileScreen() {

    val settings = LocalUserSettings.current

    Text(
        text = "Dark mode: ${settings.darkMode}"
    )
}

No need to pass settings through every intermediate composable.

🧠 Think of it like this

CompositionLocalProvider
          ↓
      Screen()
          ↓
       Header()
          ↓
      Profile()
          ↓
   UserSettings()
          ↓
   LocalUserSettings.current

The value flows down the Composition tree.

🚀 Where can it be useful?

CompositionLocal is commonly useful for values that are:

  • Needed by many composables

  • Specific to a UI subtree

  • Context/configuration-like values

  • Themes or design-system values

  • Certain UI/environment settings

For example, Compose itself uses the same pattern for concepts such as LocalContext, LocalDensity, and LocalLayoutDirection.

⚠️ One important rule:

Don't use CompositionLocal simply to avoid passing parameters.

If a value is an important dependency of a composable, explicitly passing it as a parameter can make the composable easier to understand, test, and reuse.

🔥 Simple takeaway

Parameter → when the dependency is important and explicit.

CompositionLocal → when the value is contextual and needed across a UI subtree.

Small Compose concept.

But understanding when NOT to use it is just as important as knowing how to use it.

Have you used CompositionLocal in a real project? 👇

#JetpackCompose #AndroidDevelopment #Kotlin #AndroidDev #Compose #CleanCode #AndroidDeveloper