# CompositionLocalConsumerModifierNode

Artifact: [androidx.compose.ui:ui](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/node/CompositionLocalConsumerModifierNode.kt+class:androidx.compose.ui.node.CompositionLocalConsumerModifierNode) Added in [1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.5.0) Common/AllAndroid/JVM
- Cmn

  ```
  interface CompositionLocalConsumerModifierNode : DelegatableNode
  ```

*** ** * ** ***

Implementing this interface allows your `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` subclass to read `https://developer.android.com/reference/kotlin/androidx/compose/runtime/CompositionLocal` via the `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/package-summary#(androidx.compose.ui.node.CompositionLocalConsumerModifierNode).currentValueOf(androidx.compose.runtime.CompositionLocal)` function. The values of each CompositionLocal will be resolved based on the context of the layout node that the modifier is attached to, meaning that the modifier will see the same values of each CompositionLocal as its corresponding layout node.

```kotlin
import androidx.compose.foundation.layout.Box
import androidx.compose.material3.Text
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
import androidx.compose.ui.node.DrawModifierNode
import androidx.compose.ui.node.ModifierNodeElement
import androidx.compose.ui.node.currentValueOf
import androidx.compose.ui.platform.InspectorInfo

val localBackgroundColor = compositionLocalOf { Color.White }
class BackgroundColor :
    Modifier.Node(), DrawModifierNode, CompositionLocalConsumerModifierNode {
    override fun ContentDrawScope.draw() {
        val backgroundColor = currentValueOf(localBackgroundColor)
        drawRect(backgroundColor)
        drawContent()
    }
}
val backgroundColorElement =
    object : ModifierNodeElement<BackgroundColor>() {
        override fun create() = BackgroundColor()

        override fun update(node: BackgroundColor) {}

        override fun hashCode() = System.identityHashCode(this)

        override fun equals(other: Any?) = (other === this)

        override fun InspectorInfo.inspectableProperties() {
            name = "backgroundColor"
        }
    }
fun Modifier.backgroundColor() = this then backgroundColorElement
Box(Modifier.backgroundColor()) { Text("Hello, world!") }
```

| See also |
|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` |   |
| `https://developer.android.com/reference/kotlin/androidx/compose/runtime/CompositionLocal` |   |

## Summary

| ### Extension functions |
|---|---|---|
| `T` | `<T : https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-any/index.html?> https://developer.android.com/reference/kotlin/androidx/compose/ui/node/CompositionLocalConsumerModifierNode.https://developer.android.com/reference/kotlin/androidx/compose/ui/node/CompositionLocalConsumerModifierNode#(androidx.compose.ui.node.CompositionLocalConsumerModifierNode).currentValueOf(androidx.compose.runtime.CompositionLocal)( local: https://developer.android.com/reference/kotlin/androidx/compose/runtime/CompositionLocal<T> )` Returns the current value of `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/package-summary#(androidx.compose.ui.node.CompositionLocalConsumerModifierNode).currentValueOf(androidx.compose.runtime.CompositionLocal)` at the position in the composition hierarchy of this modifier's attached layout node. | Cmn |
| `inline T` | `@https://developer.android.com/reference/kotlin/androidx/compose/ui/ExperimentalMediaQueryApi <T : https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-any/index.html?> https://developer.android.com/reference/kotlin/androidx/compose/ui/node/CompositionLocalConsumerModifierNode.https://developer.android.com/reference/kotlin/androidx/compose/ui/node/CompositionLocalConsumerModifierNode#(androidx.compose.ui.node.CompositionLocalConsumerModifierNode).mediaQuery(kotlin.Function1)(query: https://developer.android.com/reference/kotlin/androidx/compose/ui/UiMediaScope.() -> T)` Evaluates a query against the current `https://developer.android.com/reference/kotlin/androidx/compose/ui/UiMediaScope` from a `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node`. | Cmn |

### Inherited functions

From [androidx.compose.ui.node.DelegatableNode](https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode) `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` `@https://developer.android.com/reference/kotlin/androidx/annotation/EmptySuper
https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode#onDensityChange()()`

Invoked when the density changes for this node.
Cmn `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` `@https://developer.android.com/reference/kotlin/androidx/annotation/EmptySuper
https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode#onLayoutDirectionChange()()`

Invoked when the layout direction changes for this node.
Cmn

### Inherited properties

From [androidx.compose.ui.node.DelegatableNode](https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode) `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode#node()`

A reference of the `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` that holds this node's position in the node hierarchy.
Cmn

## Extension functions

### CompositionLocalConsumerModifierNode.currentValueOf

Cmn Artifact: [androidx.compose.ui:ui](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/node/CompositionLocalConsumerModifierNode.kt+function:currentValueOf)

```
fun <T : Any?> CompositionLocalConsumerModifierNode.currentValueOf(
    local: CompositionLocal<T>
): T
```

Returns the current value of `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/package-summary#(androidx.compose.ui.node.CompositionLocalConsumerModifierNode).currentValueOf(androidx.compose.runtime.CompositionLocal)` at the position in the composition hierarchy of this modifier's attached layout node.

Unlike `https://developer.android.com/reference/kotlin/androidx/compose/runtime/CompositionLocal#current()`, reads via this function are not automatically tracked by Compose. Modifiers are not able to recompose in the same way that a Composable can, and therefore can't receive updates arbitrarily for a CompositionLocal.

Because CompositionLocals may change arbitrarily, it is strongly recommended to ensure that the composition local is observed instead of being read once. If you call `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/package-summary#(androidx.compose.ui.node.CompositionLocalConsumerModifierNode).currentValueOf(androidx.compose.runtime.CompositionLocal)` inside of a modifier callback like `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/LayoutModifierNode#(androidx.compose.ui.layout.MeasureScope).measure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` or `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DrawModifierNode#(androidx.compose.ui.graphics.drawscope.ContentDrawScope).draw()`, then Compose will track the CompositionLocal read. This happens automatically, because these Compose UI phases take place in a snapshot observer that tracks which states are read. If the value of the CompositionLocal changes, and it was read inside of the measure or draw phase, then that phase will automatically be invalidated.

For all other reads of a CompositionLocal, this function will **not** notify you when the value of the local changes. `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` classes that also implement `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/ObserverModifierNode` may observe CompositionLocals arbitrarily by performing the lookup in an `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/package-summary#(androidx.compose.ui.Modifier.Node).observeReads(kotlin.Function0)` block. To continue observing values of the CompositionLocal, it must be read again in an `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/package-summary#(androidx.compose.ui.Modifier.Node).observeReads(kotlin.Function0)` block during or after the `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/ObserverModifierNode#onObservedReadsChanged()` callback is invoked. See below for an example of how to implement this observation pattern.

```kotlin
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
import androidx.compose.ui.node.ObserverModifierNode
import androidx.compose.ui.node.currentValueOf
import androidx.compose.ui.node.observeReads

val LocalValue = compositionLocalOf { "abc123" }
class ValueObserverModifierNode :
    Modifier.Node(), CompositionLocalConsumerModifierNode, ObserverModifierNode {
    private var observedValue: String? = null

    override fun onAttach() {
        onObservedReadsChanged()
    }

    override fun onDetach() {
        observedValue = null
    }

    override fun onObservedReadsChanged() {
        observeReads {
            observedValue = currentValueOf(LocalValue)
            // Do something with the new value
        }
    }
}
```

This function will fail with an `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-illegal-state-exception/index.html` if you attempt to read a CompositionLocal before the node is `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#onAttach()` or after the node is `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#onDetach()`.

| Parameters |
|---|---|
| `local: https://developer.android.com/reference/kotlin/androidx/compose/runtime/CompositionLocal<T>` | The CompositionLocal to get the current value of |

| Returns |
|---|---|
| `T` | The value provided by the nearest `https://developer.android.com/reference/kotlin/androidx/compose/runtime/CompositionLocalProvider.composable#CompositionLocalProvider(kotlin.Array,kotlin.Function0)` component that invokes, directly or indirectly, the composable function that this modifier is attached to. If `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/package-summary#(androidx.compose.ui.node.CompositionLocalConsumerModifierNode).currentValueOf(androidx.compose.runtime.CompositionLocal)` was never provided, its default value will be returned instead. |

### CompositionLocalConsumerModifierNode.mediaQuery

Cmn Artifact: [androidx.compose.ui:ui](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/MediaQuery.kt+function:mediaQuery)

```
@ExperimentalMediaQueryApi
inline fun <T : Any?> CompositionLocalConsumerModifierNode.mediaQuery(query: UiMediaScope.() -> T): T
```

Evaluates a query against the current `https://developer.android.com/reference/kotlin/androidx/compose/ui/UiMediaScope` from a `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node`.

This function is designed to be used within a `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` that implements `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/CompositionLocalConsumerModifierNode`.

If called within a snapshot-aware context like `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/LayoutModifierNode#(androidx.compose.ui.layout.MeasureScope).measure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` or `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DrawModifierNode#(androidx.compose.ui.graphics.drawscope.ContentDrawScope).draw()` callbacks, the reads within the query will be tracked, and the scope will be invalidated when the properties change.

```kotlin
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.style.size
import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
import androidx.compose.ui.mediaQuery
import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
import androidx.compose.ui.node.LayoutModifierNode
import androidx.compose.ui.node.ModifierNodeElement
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.constrainHeight
import androidx.compose.ui.unit.constrainWidth
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.offset

// Example of a custom padding modifier that uses [mediaQuery] within a [Modifier.Node].
class AdaptivePaddingNode :
    Modifier.Node(), LayoutModifierNode, CompositionLocalConsumerModifierNode {
    override fun MeasureScope.measure(
        measurable: Measurable,
        constraints: Constraints,
    ): MeasureResult {
        val isLargeScreen = mediaQuery { windowWidth > 600.dp && windowHeight > 400.dp }

        // Adjust padding or size based on the query result
        val extraPadding = if (isLargeScreen) 80.dp.roundToPx() else 16.dp.roundToPx()
        val totalPaddingOnAxis = 2 * extraPadding

        // Measure the content with added padding
        val placeable =
            measurable.measure(constraints.offset(-totalPaddingOnAxis, -totalPaddingOnAxis))

        val width = constraints.constrainWidth(placeable.width + totalPaddingOnAxis)
        val height = constraints.constrainHeight(placeable.height + totalPaddingOnAxis)

        return layout(width, height) { placeable.place(extraPadding, extraPadding) }
    }
}

class AdaptivePaddingElement : ModifierNodeElement<AdaptivePaddingNode>() {
    override fun create() = AdaptivePaddingNode()

    override fun update(node: AdaptivePaddingNode) {}

    override fun equals(other: Any?) = other === this

    override fun hashCode() = 0
}

@Stable fun Modifier.adaptivePadding(): Modifier = this.then(AdaptivePaddingElement())

Box(Modifier.adaptivePadding().background(Color.Blue).size(400.dp))
```

| Parameters |
|---|---|
| `query: https://developer.android.com/reference/kotlin/androidx/compose/ui/UiMediaScope.() -> T` | A lambda expression with `https://developer.android.com/reference/kotlin/androidx/compose/ui/UiMediaScope` as its receiver, representing the condition to evaluate. |

| Returns |
|---|---|
| `T` | The immediate result of the query. |