---
title: "rotaryScrollable"
description: "A modifier which connects rotary events with scrollable containers such as Column, LazyList and
others. [ScalingLazyColumn] has a build-in rotary support, and accepts [RotaryScrollableBehavior]
directly as a parameter.

This modifier handles rotary input devices, used for scrolling. These devices can be categorized
as high-resolution or low-resolution based on their precision.
- High-res devices: Offer finer control and can detect smaller rotations. This allows for more precise adjustments during scrolling. One example of a high-res device is the crown (also known as rotating side button), located on the side of the watch.
- Low-res devices: Have less granular control, registering larger rotations at a time. Scrolling behavior is adapted to compensate for these larger jumps. Examples include physical or virtual bezels, positioned around the screen.

This modifier supports rotary scrolling and snapping. The behaviour is configured by the provided
[RotaryScrollableBehavior]: either provide [RotaryScrollableDefaults.behavior] for scrolling
with/without fling or pass [RotaryScrollableDefaults.snapBehavior] when snap is required.

The default scroll direction of this modifier is aligned with the scroll direction of the
`Modifier.verticalScroll` and `Modifier.horizontalScroll`, (please be aware that
`Modifier.scrollable` has the opposite direction by default).

To keep the scroll direction aligned, `reverseDirection` flag should have the same value as the
`reverseScrolling` parameter in `Modifier.verticalScroll` and `Modifier.horizontalScroll`, and
the opposite value to the `reverseDirection` parameter used in `Modifier.scrollable`. When used
for horizontal scrolling, RTL/LTR orientations should be taken into account, as these can affect
the expected scroll behavior. It's recommended to use `ScrollableDefaults.reverseDirection` for
handling LTR/RTL layouts for horizontal scrolling.

This overload provides the access to [OverscrollEffect] that defines the behaviour of the rotary
over scrolling logic. Use [androidx.compose.foundation.rememberOverscrollEffect] to create an
instance of the current provided overscroll implementation.

Example of scrolling with fling:


Example of scrolling with snap:


Example of scrolling with overscroll:"
type: "modifier"
---

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

<a id='references'></a>
<div class='sourceset sourceset-android'>Android</div>


```kotlin
public fun Modifier.rotaryScrollable(
    behavior: RotaryScrollableBehavior,
    focusRequester: FocusRequester,
    reverseDirection: Boolean = false,
    overscrollEffect: OverscrollEffect? = null,
): Modifier
```


A modifier which connects rotary events with scrollable containers such as Column, LazyList and
others. `ScalingLazyColumn` has a build-in rotary support, and accepts `RotaryScrollableBehavior`
directly as a parameter.

This modifier handles rotary input devices, used for scrolling. These devices can be categorized
as high-resolution or low-resolution based on their precision.
- High-res devices: Offer finer control and can detect smaller rotations. This allows for more precise adjustments during scrolling. One example of a high-res device is the crown (also known as rotating side button), located on the side of the watch.
- Low-res devices: Have less granular control, registering larger rotations at a time. Scrolling behavior is adapted to compensate for these larger jumps. Examples include physical or virtual bezels, positioned around the screen.

This modifier supports rotary scrolling and snapping. The behaviour is configured by the provided
`RotaryScrollableBehavior`: either provide `RotaryScrollableDefaults.behavior` for scrolling
with/without fling or pass `RotaryScrollableDefaults.snapBehavior` when snap is required.

The default scroll direction of this modifier is aligned with the scroll direction of the
`Modifier.verticalScroll` and `Modifier.horizontalScroll`, (please be aware that
`Modifier.scrollable` has the opposite direction by default).

To keep the scroll direction aligned, `reverseDirection` flag should have the same value as the
`reverseScrolling` parameter in `Modifier.verticalScroll` and `Modifier.horizontalScroll`, and
the opposite value to the `reverseDirection` parameter used in `Modifier.scrollable`. When used
for horizontal scrolling, RTL/LTR orientations should be taken into account, as these can affect
the expected scroll behavior. It's recommended to use `ScrollableDefaults.reverseDirection` for
handling LTR/RTL layouts for horizontal scrolling.

This overload provides the access to `OverscrollEffect` that defines the behaviour of the rotary
over scrolling logic. Use `androidx.compose.foundation.rememberOverscrollEffect` to create an
instance of the current provided overscroll implementation.

Example of scrolling with fling:


Example of scrolling with snap:


Example of scrolling with overscroll:

#### Parameters

| | |
| --- | --- |
| behavior | Specified `RotaryScrollableBehavior` for rotary handling with snap or fling. |
| focusRequester | Used to request the focus for rotary input. Each composable with this modifier should have a separate focusRequester, and only one of them at a time can be active. We recommend using `requestFocusOnHierarchyActive` and passing this focusRequester to it to handle requesting focus, as this will guarantee the proper behavior. |
| reverseDirection | Reverses the direction of the rotary scroll. This direction should be aligned with the general touch scroll direction - and should be reversed if, for example, it was reversed in `.verticalScroll` or `.horizontalScroll` modifiers. If used with a `.scrollable` modifier - the scroll direction should be the opposite to the one specified there. When used for horizontal scrolling, RTL/LTR orientations should be taken into account, as these can affect the expected scroll behavior. It's recommended to use `ScrollableDefaults.reverseDirection` for handling LTR/RTL layouts for horizontal scrolling. |
| overscrollEffect | effect to which the deltas will be fed when the scrollable have some scrolling delta left. Pass `null` for no overscroll. If you pass an effect you should also apply `androidx.compose.foundation.overscroll` modifier. |




<div class='sourceset sourceset-android'>Android</div>


> **Deprecated** Deprecated, use another overload with overscroll parameter instead

```kotlin
public fun Modifier.rotaryScrollable(
    behavior: RotaryScrollableBehavior,
    focusRequester: FocusRequester,
    reverseDirection: Boolean = false,
): Modifier
```


A modifier which connects rotary events with scrollable containers such as Column, LazyList and
others. `ScalingLazyColumn` has a build-in rotary support, and accepts `RotaryScrollableBehavior`
directly as a parameter.

This modifier handles rotary input devices, used for scrolling. These devices can be categorized
as high-resolution or low-resolution based on their precision.
- High-res devices: Offer finer control and can detect smaller rotations. This allows for more precise adjustments during scrolling. One example of a high-res device is the crown (also known as rotating side button), located on the side of the watch.
- Low-res devices: Have less granular control, registering larger rotations at a time. Scrolling behavior is adapted to compensate for these larger jumps. Examples include physical or virtual bezels, positioned around the screen.

This modifier supports rotary scrolling and snapping. The behaviour is configured by the provided
`RotaryScrollableBehavior`: either provide `RotaryScrollableDefaults.behavior` for scrolling
with/without fling or pass `RotaryScrollableDefaults.snapBehavior` when snap is required.

Example of scrolling with fling:


Example of scrolling with snap:

#### Parameters

| | |
| --- | --- |
| behavior | Specified `RotaryScrollableBehavior` for rotary handling with snap or fling. |
| focusRequester | Used to request the focus for rotary input. Each composable with this modifier should have a separate focusRequester, and only one of them at a time can be active. We recommend using `requestFocusOnHierarchyActive` and passing this focusRequester to it to handle requesting focus, as this will guarantee the proper behavior. |
| reverseDirection | Reverse the direction of scrolling if required for consistency with the scrollable state passed via `behavior`. |




## Code Examples
### RotaryScrollSample
```kotlin
@Composable
fun RotaryScrollSample() {
    val scrollableState = rememberLazyListState()
    val focusRequester = remember { FocusRequester() }
    LazyColumn(
        modifier =
            Modifier.fillMaxSize()
                .requestFocusOnHierarchyActive()
                .rotaryScrollable(
                    behavior = RotaryScrollableDefaults.behavior(scrollableState),
                    focusRequester = focusRequester,
                ),
        horizontalAlignment = Alignment.CenterHorizontally,
        state = scrollableState,
    ) {
        items(300) {
            BasicText(
                text = "item $it",
                modifier = Modifier.background(Color.Gray),
                style = TextStyle.Default.copy(),
            )
        }
    }
}
```
### RotaryScrollWithOverscrollSample
```kotlin
@Composable
fun RotaryScrollWithOverscrollSample() {
    val scrollableState = rememberScrollState()
    val focusRequester = remember { FocusRequester() }
    val overscrollEffect = rememberOverscrollEffect()
    val screenHeightDp = LocalConfiguration.current.screenHeightDp.dp
    Column(
        Modifier.fillMaxSize()
            .requestFocusOnHierarchyActive()
            .rotaryScrollable(
                behavior = RotaryScrollableDefaults.behavior(scrollableState),
                focusRequester = focusRequester,
                overscrollEffect = overscrollEffect,
            )
            .verticalScroll(scrollableState, overscrollEffect)
            .overscroll(overscrollEffect),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text("Top")
        Spacer(modifier = Modifier.height(screenHeightDp / 2))
        Text("Scroll this list up and down with rotary input", textAlign = TextAlign.Center)
        Spacer(modifier = Modifier.height(screenHeightDp / 2))
        Text("Bottom")
    }
}
```
### RotarySnapSample
```kotlin
@Composable
fun RotarySnapSample() {
    val scrollableState = rememberLazyListState()
    val focusRequester = remember { FocusRequester() }
    LazyColumn(
        modifier =
            Modifier.fillMaxSize()
                .requestFocusOnHierarchyActive()
                .rotaryScrollable(
                    behavior =
                        RotaryScrollableDefaults.snapBehavior(
                            scrollableState,
                            // This sample has a custom implementation of
                            // RotarySnapLayoutInfoProvider which is required for snapping behavior.
                            // ScalingLazyColumn has it built-in, so it's not required there.
                            remember(scrollableState) {
                                object : RotarySnapLayoutInfoProvider {
                                    override val averageItemSize: Float
                                        get() {
                                            val items = scrollableState.layoutInfo.visibleItemsInfo
                                            return (items.fastSumBy { it.size } / items.size)
                                                .toFloat()
                                        }
                                    override val currentItemIndex: Int
                                        get() = scrollableState.firstVisibleItemIndex
                                    override val currentItemOffset: Float
                                        get() =
                                            scrollableState.firstVisibleItemScrollOffset.toFloat()
                                    override val totalItemCount: Int
                                        get() = scrollableState.layoutInfo.totalItemsCount
                                }
                            },
                        ),
                    focusRequester = focusRequester,
                ),
        horizontalAlignment = Alignment.CenterHorizontally,
        state = scrollableState,
    ) {
        items(300) {
            BasicText(text = "item $it", modifier = Modifier.background(Color.Gray).height(50.dp))
        }
    }
}
```

