# androidx.compose.material3.ripple

Common/All

## Interfaces

|---|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.DragConfiguration` | Represents the configuration for the visual representation of drag | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.FocusConfiguration` | Represents the configuration for the visual representation of focus | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.HoverConfiguration` | Represents the configuration for the visual representation of hover | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.PressConfiguration` | Represents the configuration for the visual representation of a press | Cmn |

## Classes

|---|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration` | The configuration for the ripple node created by `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/package-summary#createRippleModifierNode(androidx.compose.foundation.interaction.InteractionSource,kotlin.Function0)`. | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.DragConfiguration.Opacity` | An opacity-based drag visual. | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.FocusConfiguration.InsetRing` | An inset ring focus visual - the created ripple will show an inset focus ring. | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.FocusConfiguration.Opacity` | An opacity-based focus visual. | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.HoverConfiguration.Opacity` | An opacity-based hover visual. | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.PressConfiguration.Opacity` | An opacity-based press visual - the created ripple will show a layer with the given `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.PressConfiguration.Opacity#(kotlin.Float)` on a press. | Cmn |

## Objects

|---|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.DragConfiguration.None` | No drag visual - the created ripple will not show anything for drag. | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.FocusConfiguration.None` | No focus visual - the created ripple will not show anything for focus. | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.HoverConfiguration.None` | No hover visual - the created ripple will not show anything for hover. | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration.PressConfiguration.None` | No press visual - the created ripple will not show anything for press. | Cmn |

## Top-level functions summary

|---|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode` | `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/package-summary#createRippleModifierNode(androidx.compose.foundation.interaction.InteractionSource,kotlin.Function0)( interactionSource: https://developer.android.com/reference/kotlin/androidx/compose/foundation/interaction/InteractionSource, rippleNodeConfiguration: () -> https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration )` Creates a Ripple node using the values provided. | Cmn |

## Top-level functions

### createRippleModifierNode

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

```
fun createRippleModifierNode(
    interactionSource: InteractionSource,
    rippleNodeConfiguration: () -> RippleNodeConfiguration
): DelegatableNode
```

Creates a Ripple node using the values provided.

A Ripple is a Material 3 node that expresses different `https://developer.android.com/reference/kotlin/androidx/compose/foundation/interaction/Interaction`s by drawing ripple animations, and state layers, and other graphical effects.

A Ripple responds to `https://developer.android.com/reference/kotlin/androidx/compose/foundation/interaction/PressInteraction.Press` by starting a new `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleAnimation`, and responds to other `https://developer.android.com/reference/kotlin/androidx/compose/foundation/interaction/Interaction`s by showing a fixed state layer with varying alpha values depending on the `https://developer.android.com/reference/kotlin/androidx/compose/foundation/interaction/Interaction`, or an inset ring for `https://developer.android.com/reference/kotlin/androidx/compose/foundation/interaction/FocusInteraction`, depending on the supplied `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration`.

This Ripple node is a low level building block for building IndicationNodeFactory implementations that use a Ripple - higher level design system libraries such as material3 provide ripple implementations using this node internally. In most cases you should use those factories directly: this node exists for design system libraries to delegate their Ripple implementation to, after querying any required theme values for customizing the Ripple.

NOTE: when using this factory with `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#delegate(androidx.compose.ui.node.DelegatableNode)`, ensure that the node is created once or `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatingNode#undelegate(androidx.compose.ui.node.DelegatableNode)` is called in `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#onDetach()`. Repeatedly delegating to a new node returned by this method in `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node#onAttach()` without removing the old one will result in multiple ripple nodes being attached to the node.

```kotlin
import androidx.compose.foundation.IndicationNodeFactory
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.material3.ripple.RippleNodeConfiguration
import androidx.compose.material3.ripple.createRippleModifierNode
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorProducer
import androidx.compose.ui.graphics.isSpecified
import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
import androidx.compose.ui.node.DelegatableNode
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.ObserverModifierNode
import androidx.compose.ui.node.currentValueOf
import androidx.compose.ui.node.observeReads
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

/** Example CompositionLocals for a custom design system theme. */
val LocalCustomRippleColor: ProvidableCompositionLocal<Color> = compositionLocalOf { Color.Red }
val LocalCustomRippleEnabled: ProvidableCompositionLocal<Boolean> = compositionLocalOf { true }

/**
 * A custom [Modifier.Node] that queries design system theme values and delegates to
 * [createRippleModifierNode].
 */
class CustomRippleNode(
    private val interactionSource: InteractionSource,
    private val bounded: Boolean,
    private val radius: Dp,
    private val color: Color,
) : DelegatingNode(), CompositionLocalConsumerModifierNode, ObserverModifierNode {
    private var rippleNode: DelegatableNode? = null

    private val calculateColor = ColorProducer {
        if (color.isSpecified) {
            color
        } else {
            currentValueOf(LocalCustomRippleColor)
        }
    }

    private val rippleNodeConfiguration =
        RippleNodeConfiguration(
            isBounded = bounded,
            radius = radius,
            color = calculateColor,
            pressConfiguration =
                RippleNodeConfiguration.PressConfiguration.Opacity(alpha = 0.24f),
            focusConfiguration =
                RippleNodeConfiguration.FocusConfiguration.Opacity(alpha = 0.24f),
            hoverConfiguration =
                RippleNodeConfiguration.HoverConfiguration.Opacity(alpha = 0.08f),
            dragConfiguration =
                RippleNodeConfiguration.DragConfiguration.Opacity(alpha = 0.16f),
        )

    override fun onAttach() {
        updateConfiguration()
    }

    override fun onObservedReadsChanged() {
        updateConfiguration()
    }

    private fun updateConfiguration() {
        observeReads {
            val isEnabled = currentValueOf(LocalCustomRippleEnabled)
            if (isEnabled) {
                if (rippleNode == null) {
                    attachNewRipple()
                }
            } else {
                removeRipple()
            }
        }
    }

    private fun attachNewRipple() {
        rippleNode =
            delegate(
                createRippleModifierNode(
                    interactionSource = interactionSource,
                    rippleNodeConfiguration = { rippleNodeConfiguration },
                )
            )
    }

    private fun removeRipple() {
        rippleNode?.let { undelegate(it) }
        rippleNode = null
    }
}

/** A custom [IndicationNodeFactory] that creates a [CustomRippleNode]. */
class CustomRipple(
    private val bounded: Boolean = true,
    private val radius: Dp = Dp.Unspecified,
    private val color: Color = Color.Unspecified,
) : IndicationNodeFactory {
    override fun create(interactionSource: InteractionSource): DelegatableNode {
        return CustomRippleNode(interactionSource, bounded, radius, color)
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other !is CustomRipple) return false
        if (bounded != other.bounded) return false
        if (radius != other.radius) return false
        if (color != other.color) return false
        return true
    }

    override fun hashCode(): Int {
        var result = bounded.hashCode()
        result = 31 * result + radius.hashCode()
        result = 31 * result + color.hashCode()
        return result
    }
}

val interactionSource = remember { MutableInteractionSource() }

Box(
    modifier =
        Modifier.size(100.dp)
            .clickable(
                interactionSource = interactionSource,
                indication = CustomRipple(color = Color.Blue),
                onClick = {},
            )
)
```

| Parameters |
|---|---|
| `interactionSource: https://developer.android.com/reference/kotlin/androidx/compose/foundation/interaction/InteractionSource` | the `https://developer.android.com/reference/kotlin/androidx/compose/foundation/interaction/InteractionSource` used to determine the state of the ripple. |
| `rippleNodeConfiguration: () -> https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration` | the `https://developer.android.com/reference/kotlin/androidx/compose/material3/ripple/RippleNodeConfiguration` that will be applied to the ripple depending on the state of the ripple. This lambda may be invoked repeatedly, so consider caching values of configuration when they haven't changed. |

| Returns |
|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode` | a `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode` that handles drawing the ripple and state layers. |