Skip to content

About

Compose DND is a library that allows you to easily add drag and drop functionality to your Jetpack Compose or Compose Multiplatform projects.

Topics

Resources

Code of conduct

Stars

545 stars

Watchers

2 watching

Forks

Repository files navigation

Compose DND

A library that allows you to easily add drag and drop functionality to your Jetpack Compose or Compose Multiplatform projects.

Kotlin Compose Apache-2.0 BuildPassing Maven Central

A Kanban board built with Compose DND: cards move between columns and columns reorder

Try the live demo · Documentation · Sample app

  • One API for every platform -- Android, iOS, desktop and web share the same code.
  • Just modifiers -- add draggableItem, dropTarget or reorderableItem to the composables you already have.
  • Works inside scrollables -- long press to drag, auto scroll at the edges, lazy lists and grids.
  • You own the data -- the library reports what happens, your state decides what changes.
Support Palestine

What you can build

Every clip below is a screen of the sample app. Click one to open its guide.

Drag and drop
Drag and drop

draggableItem + dropTarget
Reorder a list
Reorder a list

reorderableItem
Drag handle
Drag handle

Only the grip starts the drag
Move between lists
Move between lists

One state, many lists
Auto scroll
Auto scroll

Lists, grids and staggered grids
Scroll across columns
Scroll across columns

Auto scroll on both axes
Drag to select
Drag to select

Then drag the selection as a group
Free-form placement
Free-form placement

Drop anywhere, snap to a grid
Copy on drop
Copy on drop

A palette that keeps its items
Conditional drop
Conditional drop

Targets choose what they accept
Drop strategies
Drop strategies

Pick the target under the item
Axis lock
Axis lock

Horizontal or vertical only

Features

  • Drag and Drop -- Drag items from one location and drop them onto designated targets
  • Reorder Lists -- Reorder items within a list, a grid, or across several lists
  • Auto Scroll -- Scroll lazy lists, grids, staggered grids and scrollable containers when an item is held near an edge, in any layout direction
  • Drag to Select / Multi-Select -- Extend a selection by dragging across items, then drag the whole selection as a group
  • Free-Form Placement -- Drop items anywhere on a board, with the drop animation landing exactly where they snap
  • Drop Strategies -- Choose which drop target wins when the dragged item covers several, or write your own
  • Drag Handle -- Restrict the drag gesture to a specific handle area within the item
  • Axis Lock -- Constrain dragging to the horizontal or vertical axis
  • Conditional Drop -- Control which drop targets accept which dragged items
  • Long Press to Drag -- Keep taps and scrolling working on draggable items
  • Drag Lifecycle Callbacks -- onDragStart and onDragEnd on every draggable item, so you can persist state once per drag
  • Drop Animation -- Smooth spring-based animations when items are dropped
  • Custom Drag Shadow -- Provide a custom composable to display while an item is being dragged

Platform Support

Platform Supported
Android Yes
iOS Yes
Desktop Yes
Web (JS) Yes
Web (WASM) Yes

Installation

Maven Central

Version Compatibility

Kotlin version Compose version Compose DND version
2.4.21 1.12.1 1.0.0-alpha02
2.3.20 1.10.3 1.0.0-alpha01

Add the following dependency to your module build.gradle.kts file:

implementation("com.mohamedrejeb.dnd:compose-dnd:1.0.0-alpha02")

For Kotlin Multiplatform projects, add the dependency to your commonMain source set:

kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("com.mohamedrejeb.dnd:compose-dnd:1.0.0-alpha02")
        }
    }
}

1.0.0-alpha01 is the first 1.0 alpha. It deprecates ReorderState, rememberReorderState, and ReorderContainer in favor of DragAndDropState everywhere -- see the migration guide if you're upgrading from 0.5.0.

Usage

Drag and Drop

Create a DragAndDropState, wrap your content with DragAndDropContainer, and use the draggableItem and dropTarget modifiers:

val dragAndDropState = rememberDragAndDropState<String>()

DragAndDropContainer(
    state = dragAndDropState,
) {
    val isDragging = dragAndDropState.isDragging("item-1")

    Text(
        text = "Drag me",
        modifier = Modifier
            .graphicsLayer { alpha = if (isDragging) 0f else 1f }
            .draggableItem(
                key = "item-1",
                data = "Hello",
                state = dragAndDropState,
                draggableContent = {
                    Text("Drag me") // Shown as the drag shadow
                },
            ),
    )

    Box(
        modifier = Modifier
            .dropTarget(
                key = "target-1",
                state = dragAndDropState,
                onDrop = { state ->
                    println("Dropped: ${state.data}")
                },
            )
    ) {
        Text("Drop here")
    }
}

Reorder List

The reorderableItem modifier makes an item both draggable and a drop target, which is all a sortable list needs:

val dndState = rememberDragAndDropState<String>()

DragAndDropContainer(
    state = dndState,
) {
    LazyColumn {
        items(items, key = { it }) { item ->
            Text(
                text = item,
                modifier = Modifier
                    .graphicsLayer { alpha = if (dndState.isDragging(item)) 0f else 1f }
                    .reorderableItem(
                        key = item,
                        data = item,
                        state = dndState,
                        onDragEnter = { state ->
                            items = items.toMutableList().apply {
                                val index = indexOf(item)
                                if (index != -1) {
                                    remove(state.data)
                                    add(index, state.data)
                                }
                            }
                        },
                        draggableContent = {
                            Text(item)
                        },
                    ),
            )
        }
    }
}

Enable/Disable Drag and Drop

Toggle drag and drop at the container level:

DragAndDropContainer(
    state = dragAndDropState,
    enabled = false,
) { }

Or for a specific item by passing enabled = false to the draggableItem or reorderableItem modifier.

Prefer wrapping composables instead of modifiers? The DraggableItem and ReorderableItem wrapper composables offer the same features - see the documentation.

For more details and advanced features (auto scroll, drop strategies, drag handles, axis lock), check out the documentation and the sample project.

Contribution

If you've found an error in this library, please file an issue.

Feel free to help out by sending a pull request.

Code of Conduct

Find this library useful?

Support it by joining stargazers for this repository.

Also, follow me on GitHub for more libraries!

You can always buy me a coffee:

Buy me a coffee

License

Copyright 2023 Mohamed Rejeb

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

   http://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.

About

Compose DND is a library that allows you to easily add drag and drop functionality to your Jetpack Compose or Compose Multiplatform projects.

Topics

Resources

Code of conduct

Stars

545 stars

Watchers

2 watching

Forks

Releases

Used by

Contributors

Languages