Skip to content

Releases: devgalib/compose-reorderable

v1.0.0

02 Nov 11:23

Choose a tag to compare

Compose Reorderable Library - v1.0.0

A Jetpack Compose library to make LazyColumn, LazyRow, and LazyGrid reorderable with drag & drop. Works seamlessly with Material3 theme and supports both keyed and indexed-only lists.

Features

  • Reorder LazyColumn (vertical list)
  • Reorder LazyRow (horizontal list)
  • Reorder LazyVerticalGrid & LazyHorizontalGrid
  • Animated elevation during dragging
  • Customizable drag handle
  • Simple and lightweight

Usage

For LazyList:

val state = rememberReorderableLazyListState(onMove = { from, to -> 
    data.value = data.value.toMutableList().apply {
        add(to.index, removeAt(from.index))
    }
})

For LazyGrid:

val state = rememberReorderableLazyGridState(
    onMove = { from, to ->
        data.value = data.value.toMutableList().apply {
            add(to.index, removeAt(from.index))
        }
    }
)

2. Add the reorderable modifier

⚙️ How to Use (Vertical & Horizontal)

1. Vertical Reorderable List (LazyColumn)

@Composable
fun VerticalReorderList() {
    val data = remember { mutableStateOf(List(100) { "Item $it" }) }
    val state = rememberReorderableLazyListState(onMove = { from, to ->
        data.value = data.value.toMutableList().apply {
            add(to.index, removeAt(from.index))
        }
    })
    LazyColumn(
        state = state.listState,
        modifier = Modifier
            .reorderable(state)
            .detectReorderAfterLongPress(state)
    ) {
        items(data.value, { it }) { item ->
            ReorderableItem(state, key = item) { isDragging ->
                val elevation = animateDpAsState(if (isDragging) 16.dp else 0.dp)
                Column(
                    modifier = Modifier
                        .shadow(elevation.value)
                        .background(MaterialTheme.colorScheme.surface)
                ) {
                    Text(item)
                }
            }
        }
    }
}

2. Vertical Reorderable Grid (LazyVerticalGrid)

@Composable
fun VerticalReorderGrid() {
    val data = remember { mutableStateOf(List(100) { "Item $it" }) }
    val state = rememberReorderableLazyGridState(
        dragCancelledAnimation = NoDragCancelledAnimation(),
        onMove = { from, to ->
            data.value = data.value.toMutableList().apply {
                add(to.index, removeAt(from.index))
            }
        }
    )
    LazyVerticalGrid(
        columns = GridCells.Fixed(4),
        state = state.gridState,
        modifier = Modifier.reorderable(state)
    ) {
        items(data.value, { it }) { item ->
            ReorderableItem(state, key = item, defaultDraggingModifier = Modifier) { isDragging ->
                Box(
                    modifier = Modifier
                        .aspectRatio(1f)
                        .background(MaterialTheme.colorScheme.surface)
                ) {
                    Text(
                        text = item,
                        modifier = Modifier.detectReorderAfterLongPress(state)
                    )
                }
            }
        }
    }
}

3. Horizontal Reorderable List (LazyRow)

@Composable
fun HorizontalReorderList() {
    val data = remember { mutableStateOf(List(100) { "Item $it" }) }
    val state = rememberReorderableLazyListState(onMove = { from, to ->
        data.value = data.value.toMutableList().apply {
            add(to.index, removeAt(from.index))
        }
    })
    LazyRow(
        state = state.listState,
        modifier = Modifier
            .reorderable(state)
            .detectReorderAfterLongPress(state)
    ) {
        items(data.value, { it }) { item ->
            ReorderableItem(state, key = item) { isDragging ->
                val elevation = animateDpAsState(if (isDragging) 16.dp else 0.dp)
                Column(
                    modifier = Modifier
                        .shadow(elevation.value)
                        .background(MaterialTheme.colorScheme.surface)
                        .padding(8.dp)
                ) {
                    Text(item)
                }
            }
        }
    }
}

4. Horizontal Reorderable Grid (LazyHorizontalGrid)

@Composable
fun HorizontalReorderGrid() {
    val data = remember { mutableStateOf(List(100) { "Item $it" }) }
    val state = rememberReorderableLazyGridState(
        dragCancelledAnimation = NoDragCancelledAnimation(),
        onMove = { from, to ->
            data.value = data.value.toMutableList().apply {
                add(to.index, removeAt(from.index))
            }
        }
    )
    LazyHorizontalGrid(
        rows = GridCells.Fixed(2),
        state = state.gridState,
        modifier = Modifier.reorderable(state)
    ) {
        items(data.value, { it }) { item ->
            ReorderableItem(state, key = item, defaultDraggingModifier = Modifier) { isDragging ->
                Box(
                    modifier = Modifier
                        .aspectRatio(1f)
                        .background(MaterialTheme.colorScheme.surface)
                        .padding(4.dp)
                ) {
                    Text(
                        text = item,
                        modifier = Modifier.detectReorderAfterLongPress(state)
                    )
                }
            }
        }
    }
}

📝 Notes

  • First visible item may not animate — this is a known issue.
  • Drag handle and animation can be customized using detectReorder and defaultDraggingModifier.
  • Works with Jetpack Compose Material3 theme.
  • Supports keyed and indexed-only lists (animated items only work with keyed lists).

👤 Author

Asadullah Hil Galib

GitHub: https://github.com/codergalib2005

YouTube: https://www.youtube.com/@devgalib

📜 License

Copyright 2025 Asadullah Hil Galib

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.