---
title: "scrollableArea"
description: "Configure a component to act as a scrollable area. A scrollable area clips its content to its
bounds, renders overscroll, and handles scroll gestures such that the content, not the viewport,
moves with the user's gestures.

This modifier is a building block for creating custom scrollable containers, and serves as a
higher-level abstraction over [androidx.compose.foundation.gestures.scrollable]. For simpler use
cases, prefer higher-level components that are built with `scrollableArea`, such as
[verticalScroll] and [androidx.compose.foundation.lazy.LazyColumn]. For example, [verticalScroll]
offsets the content in the viewport out of the box to have scrollable container behavior.

The primary distinction between `scrollable` and `scrollableArea` is in how scroll deltas are
handled. `scrollableArea` inverts the deltas to provide a natural \"content-moving\" experience.
For instance, dragging a finger up results in a positive scroll delta, which accommodates content
moving upwards within the layout. In contrast, the lower-level `scrollable` provides raw,
un-inverted deltas, which is useful for custom gesture handling that isn't directly tied to
content scrolling.

The direction of scrolling is automatically adjusted based on the [orientation], the current
[androidx.compose.ui.platform.LocalLayoutDirection], and the [reverseScrolling] flag. Setting
[reverseScrolling] to `true` is useful for layouts that grow from the end of the container to the
beginning, like a chat feed. In such cases, the content within the container should also be laid
out in reverse. The following table summarizes the resulting scroll delta for a user's drag
gesture:

| `orientation` | `LayoutDirection` | `reverseScrolling` | User Gesture | Scroll Delta |
|"
type: "modifier"
---

<div class='type'>Compose Modifier</div>

<a id='references'></a>
<div class='sourceset sourceset-common'>Common</div>


```kotlin
fun Modifier.scrollableArea(
    state: ScrollableState,
    orientation: Orientation,
    enabled: Boolean = true,
    reverseScrolling: Boolean = false,
    flingBehavior: FlingBehavior? = null,
    interactionSource: MutableInteractionSource? = null,
    bringIntoViewSpec: BringIntoViewSpec? = null,
): Modifier
```


Configure a component to act as a scrollable area. A scrollable area clips its content to its
bounds, renders overscroll, and handles scroll gestures such that the content, not the viewport,
moves with the user's gestures.

This modifier is a building block for creating custom scrollable containers, and serves as a
higher-level abstraction over `androidx.compose.foundation.gestures.scrollable`. For simpler use
cases, prefer higher-level components that are built with `scrollableArea`, such as
`verticalScroll` and `androidx.compose.foundation.lazy.LazyColumn`. For example, `verticalScroll`
offsets the content in the viewport out of the box to have scrollable container behavior.

The primary distinction between `scrollable` and `scrollableArea` is in how scroll deltas are
handled. `scrollableArea` inverts the deltas to provide a natural "content-moving" experience.
For instance, dragging a finger up results in a positive scroll delta, which accommodates content
moving upwards within the layout. In contrast, the lower-level `scrollable` provides raw,
un-inverted deltas, which is useful for custom gesture handling that isn't directly tied to
content scrolling.

The direction of scrolling is automatically adjusted based on the `orientation`, the current
`androidx.compose.ui.platform.LocalLayoutDirection`, and the `reverseScrolling` flag. Setting
`reverseScrolling` to `true` is useful for layouts that grow from the end of the container to the
beginning, like a chat feed. In such cases, the content within the container should also be laid
out in reverse. The following table summarizes the resulting scroll delta for a user's drag
gesture:

| `orientation` | `LayoutDirection` | `reverseScrolling` | User Gesture | Scroll Delta |
|---------------|-------------------|--------------------|--------------|--------------|
| `Vertical`    | `Ltr` and `Rtl`   | `false`            | Drag Up      | Positive     |
| `Vertical`    | `Ltr` and `Rtl`   | `true`             | Drag Up      | Negative     |
| `Horizontal`  | `Ltr`             | `false`            | Drag Left    | Positive     |
| `Horizontal`  | `Ltr`             | `true`             | Drag Left    | Negative     |
| `Horizontal`  | `Rtl`             | `false`            | Drag Left    | Negative     |
| `Horizontal`  | `Rtl`             | `true`             | Drag Left    | Positive     |

This `scrollableArea` overload uses overscroll provided through `LocalOverscrollFactory` by
default. See the other overload to manually provide an `OverscrollEffect` instance, or disable
overscroll.

#### Parameters

| | |
| --- | --- |
| state | The `ScrollableState` of the component. |
| orientation | The `Orientation` of scrolling. |
| enabled | Whether scrolling is enabled. |
| flingBehavior | logic describing fling behavior when drag has finished with velocity. If `null`, default from `ScrollableDefaults.flingBehavior` will be used. |
| reverseScrolling | reverses the direction of scrolling. This is useful for experiences where new items appear at the end and the list grows backwards. When `reverseScrolling` is true, the layout of the content inside the container should also be reversed by the user. For example, in a `verticalScroll`, setting `reverseScrolling` true will cause items to be laid out from bottom to top. When using `scrollableArea` directly in custom list implementations, ensure your layout logic also arranges content in reverse order (e.g. from end to start) to match the scroll behavior. |
| interactionSource | an optional hoisted `MutableInteractionSource` for observing and emitting `Interaction`s for this scrollable area. Note that if `null` is provided, interactions will still happen internally. |
| bringIntoViewSpec | The configuration that this scrollable area should use to perform scrolling when scroll requests are received from the focus system. If `null` is provided, the system will use the behavior provided by `androidx.compose.foundation.gestures.LocalBringIntoViewSpec` which by default has a platform dependent implementation. |




<div class='sourceset sourceset-common'>Common</div>


```kotlin
fun Modifier.scrollableArea(
    state: ScrollableState,
    orientation: Orientation,
    overscrollEffect: OverscrollEffect?,
    enabled: Boolean = true,
    reverseScrolling: Boolean = false,
    flingBehavior: FlingBehavior? = null,
    interactionSource: MutableInteractionSource? = null,
    bringIntoViewSpec: BringIntoViewSpec? = null,
): Modifier
```


Configure a component to act as a scrollable area. A scrollable area clips its content to its
bounds, renders overscroll, and handles scroll gestures such that the content, not the viewport,
moves with the user's gestures.

This modifier is a building block for creating custom scrollable containers, and serves as a
higher-level abstraction over `androidx.compose.foundation.gestures.scrollable`. For simpler use
cases, prefer higher-level components that are built with `scrollableArea`, such as
`verticalScroll` and `androidx.compose.foundation.lazy.LazyColumn`. For example, `verticalScroll`
offsets the content in the viewport out of the box to have scrollable container behavior.

The primary distinction between `scrollable` and `scrollableArea` is in how scroll deltas are
handled. `scrollableArea` inverts the deltas to provide a natural "content-moving" experience.
For instance, dragging a finger up results in a positive scroll delta, which accommodates content
moving upwards within the layout. In contrast, the lower-level `scrollable` provides raw,
un-inverted deltas, which is useful for custom gesture handling that isn't directly tied to
content scrolling.

The direction of scrolling is automatically adjusted based on the `orientation`, the current
`androidx.compose.ui.platform.LocalLayoutDirection`, and the `reverseScrolling` flag. Setting
`reverseScrolling` to `true` is useful for layouts that grow from the end of the container to the
beginning, like a chat feed. In such cases, the content within the container should also be laid
out in reverse. The following table summarizes the resulting scroll delta for a user's drag
gesture:

| `orientation` | `LayoutDirection` | `reverseScrolling` | User Gesture | Scroll Delta |
|---------------|-------------------|--------------------|--------------|--------------|
| `Vertical`    | `Ltr` and `Rtl`   | `false`            | Drag Up      | Positive     |
| `Vertical`    | `Ltr` and `Rtl`   | `true`             | Drag Up      | Negative     |
| `Horizontal`  | `Ltr`             | `false`            | Drag Left    | Positive     |
| `Horizontal`  | `Ltr`             | `true`             | Drag Left    | Negative     |
| `Horizontal`  | `Rtl`             | `false`            | Drag Left    | Negative     |
| `Horizontal`  | `Rtl`             | `true`             | Drag Left    | Positive     |

This overload allows providing `OverscrollEffect` that will be rendered within the scrollable
area. See the other overload of `scrollableArea` in order to use a default `OverscrollEffect`
provided by `LocalOverscrollFactory`.

#### Parameters

| | |
| --- | --- |
| state | The `ScrollableState` of the component. |
| orientation | The `Orientation` of scrolling. |
| overscrollEffect | the `OverscrollEffect` that will be used to render overscroll for this scrollable area. Note that the `OverscrollEffect.node` will be applied internally as well - you do not need to use Modifier.overscroll separately. |
| enabled | Whether scrolling is enabled. |
| flingBehavior | logic describing fling behavior when drag has finished with velocity. If `null`, default from `ScrollableDefaults.flingBehavior` will be used. |
| reverseScrolling | reverses the direction of scrolling. This is useful for experiences where new items appear at the end and the list grows backwards. When `reverseScrolling` is true, the layout of the content inside the container should also be reversed by the user. For example, in a `verticalScroll`, setting `reverseScrolling` true will cause items to be laid out from bottom to top. When using `scrollableArea` directly in custom list implementations, ensure your layout logic also arranges content in reverse order (e.g. from end to start) to match the scroll behavior. |
| interactionSource | an optional hoisted `MutableInteractionSource` for observing and emitting `Interaction`s for this scrollable area. Note that if `null` is provided, interactions will still happen internally. |
| bringIntoViewSpec | The configuration that this scrollable area should use to perform scrolling when scroll requests are received from the focus system. If `null` is provided, the system will use the behavior provided by `androidx.compose.foundation.gestures.LocalBringIntoViewSpec` which by default has a platform dependent implementation. |




## Code Examples
### ScrollableAreaSample
```kotlin
@Composable
fun ScrollableAreaSample() {
    // This sample demonstrates how to create custom scrollable containers using the scrollableArea
    // modifier.
    // This ScrollableAreaSampleScrollState holds the scroll position and other relevant
    // information. It implements the ScrollableState interface, making it compatible with the
    // scrollableArea modifier, and is similar in function to the ScrollState used with
    // Modifier.verticalScroll.
    val scrollState = rememberScrollableAreaSampleScrollState()
    // For lists with many items, consider using a LazyLayout instead
    Layout(
        modifier =
            Modifier.size(150.dp)
                .scrollableArea(scrollState, Orientation.Vertical)
                .background(Color.LightGray),
        content = {
            repeat(40) {
                Text(
                    modifier = Modifier.padding(vertical = 2.dp),
                    text = "Item $it",
                    fontSize = 24.sp,
                    textAlign = TextAlign.Center,
                )
            }
        },
    ) { measurables, constraints ->
        var totalHeight = 0
        val childConstraints = constraints.copy(minWidth = 0, minHeight = 0)
        val placeables =
            measurables.map { measurable ->
                val placeable = measurable.measure(childConstraints)
                totalHeight += placeable.height
                placeable
            }
        val viewportHeight = constraints.maxHeight
        // Update the maximum scroll value to not scroll beyond limits and stop when scroll
        // reaches the end.
        scrollState.maxValue = (totalHeight - viewportHeight).coerceAtLeast(0)
        // Position the children within the layout.
        layout(constraints.maxWidth, viewportHeight) {
            // The current vertical scroll position, in pixels.
            val scrollY = scrollState.value
            val viewportCenterY = scrollY + viewportHeight / 2
            var placeableLayoutPositionY = 0
            placeables.forEach { placeable ->
                // This sample applies a scaling effect to items based on their distance
                // from the center, creating a wheel-like effect.
                val itemCenterY = placeableLayoutPositionY + placeable.height / 2
                val distanceFromCenter = abs(itemCenterY - viewportCenterY)
                val normalizedDistance =
                    (distanceFromCenter / (viewportHeight / 2f)).fastCoerceIn(0f, 1f)
                // Items scale between 0.4 at the edges of the viewport and 1 at the center.
                val scaleFactor = 1f - (normalizedDistance * 0.6f)
                // Place the item horizontally centered with a layer transformation for
                // scaling to achieve wheel-like effect.
                placeable.placeRelativeWithLayer(
                    x = constraints.maxWidth / 2 - placeable.width / 2,
                    // Offset y by the scroll position to make placeable visible in the viewport.
                    y = placeableLayoutPositionY - scrollY,
                ) {
                    scaleX = scaleFactor
                    scaleY = scaleFactor
                }
                // Move to the next item's vertical position.
                placeableLayoutPositionY += placeable.height
            }
        }
    }
}
```

