Library / SDK
MohamedRejeb/compose-dnd avatar
MohamedRejeb/compose-dnd

Compose DND: drag and drop as Compose modifiers

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

545 stars24 forksKotlinApache-2.0

At a glance

What is it?
Compose DND is a Kotlin library that adds drag and drop to Jetpack Compose and Compose Multiplatform through modifiers rather than a special component, with draggableItem, dropTarget and reorderableItem on the composables you already have. The library reports events and leaves the data to you, and it is currently published as a 1.0.0 alpha.
Who is it for?
Compose DND fits a Compose developer building a board, a reorderable list or a palette and who wants the same drag behaviour on Android, iOS, desktop and web from one code path, and who is willing to work against a 1.0.0 alpha API.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly Kotlin, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Three modifiers instead of a special composable

Compose DND is a library that allows you to easily add drag and drop functionality to your Jetpack Compose or Compose Multiplatform projects. The design decision that defines it is that it is applied through modifiers rather than through wrapper composables, and the README is blunt about the point: just modifiers, add `draggableItem`, `dropTarget` or `reorderableItem` to the composables you already have.

That choice has an immediate consequence. A drag-and-drop implementation built on wrapper composables has to own the child content, so it needs a slot API, it needs to forward layout modifiers, and it ends up in a fight with the layout system whenever the child wants to be measured differently. Modifiers sit in the modifier chain of the item you already wrote, which means the item keeps its own layout and its own content, and the drag behaviour is layered on top.

The other headline property is that the library does not hold your data. The README puts it as you own the data, the library reports what happens, your state decides what changes. So a drag start, a drag end and a drop event are reported to you as callbacks, and where the item ends up is decided by your own state update. That is a different model from the drag-and-drop libraries for the view system, which tend to own an adapter and mutate a list.

The library is written in Kotlin, licensed Apache-2.0, and the default branch is main. The badges in the README give the Kotlin version as 2.4.21 and Compose as 1.12.1, and the artifact is on Maven Central under the group com.mohamedrejeb.dnd with the artifact name compose-dnd. The last push to the repository was on 2026-10-12, and the recent releases are v1.0.0-alpha02 on the same date, v1.0.0-alpha01 on 2026-10-11 and v0.5.0 on 2026-07-08.

One code path across Android, iOS, desktop and web

The first bullet in the README's feature list is that there is one API for every platform, with Android, iOS, desktop and web sharing the same code. That is the claim that matters most for a Compose Multiplatform project, and it is what the repository layout is built around.

The sample directory holds a separate module for each target: sample/android, sample/common, sample/desktop, sample/iosApp and sample/web. The common module is where the shared UI lives, at sample/common/src/commonMain/kotlin/ui, and the README's table of what you can build points at exactly that path, saying every clip is a screen of the sample app and that clicking one opens its guide. So the same source file is being rendered on five platforms, and the demo gifs in the documentation are the result.

The consequence for a reader is that the library is not an Android library that happens to compile elsewhere. Drag and drop on the web, on iOS and on desktop goes through the same modifier and the same callbacks, and the platform differences are handled inside the library. For a team shipping a Compose Multiplatform app, that is the difference between one drag implementation and three.

The repository is a Gradle project with a convention-plugins/ directory and a spotless/ directory, a mkdocs.yml for the documentation site, a docs/ directory, a CHANGELOG.md, and a scripts/ directory. The gradlew and gradlew.bat wrapper scripts are at the root, and the library module itself is in the compose-dnd/ directory, separate from the sample.

The feature list as a set of interaction decisions

The features section reads as a list of interaction problems solved, and it is worth reading as a set of decisions rather than a shopping list, because several of them exist because a naive drag implementation gets them wrong.

The core is drag and drop, dragging items from one location and dropping them onto designated targets, and reorder lists, reordering items within a list, a grid, or across several lists. Then there is the set that makes drag usable in a real screen. Long press to drag keeps taps and scrolling working on draggable items, which is the difference between a list you can scroll and a list that fights you. Auto scroll handles lazy lists, grids, staggered grids and scrollable containers when an item is held near an edge, in any layout direction, and the demo clips show it both at a single edge and with auto scroll on both axes for a board that scrolls across columns.

The set that changes what a drag can express is more interesting. Drag to select and multi-select let you extend a selection by dragging across items and then drag the whole selection as a group. Free-form placement drops items anywhere on a board, with the drop animation landing exactly where they snap. Conditional drop lets targets choose which items they accept. Drop strategies let you choose which drop target wins when the dragged item covers several, or write your own.

Three smaller modifiers round it out. A drag handle restricts the drag gesture to a specific handle area within the item, so the rest of the card stays tappable. Axis lock constrains dragging to the horizontal or vertical axis. And the drag lifecycle callbacks, `onDragStart` and `onDragEnd` on every draggable item, exist so you can persist state once per drag rather than on every frame.

The drop animation is described as smooth spring-based animations, and the custom drag shadow lets you supply your own composable to display while an item is being dragged, which is how the free-form board and the Kanban demo get their visual identity.

Scrollables, long press and the sample app as reference

The bullet that says it works inside scrollables is the one that has broken most drag implementations in Compose, so it is worth being precise about what the README claims. Long press to drag, auto scroll at the edges, and lazy lists and grids.

The mechanism behind the long press requirement is gesture arbitration. A drag and a scroll are both pointer gestures on the same surface, and a scrollable will normally consume the vertical drag. The long press disambiguates them: the pointer has to be held before the drag begins, so a flick still scrolls, and a press-and-hold starts a drag. That also means a drag cannot start from a single quick touch, which is the behaviour a designer has to expect.

The auto scroll behaviour has to work in any layout direction, which covers the horizontal case of a Kanban board with columns that scroll sideways as well as the vertical case of a long list. The demo clip labelled scroll across columns is precisely that case, and the fact that the README lists staggered grids and scrollable containers separately from lazy lists and grids suggests the auto scroll is implemented against the scrollable abstraction rather than against a particular list composable.

For a developer learning the API, the sample app is the reference the project points at. The repository has a sample app and the README links it directly, and the documentation site is a live demo at mohamedrejeb.github.io/compose-dnd/demo/ with per-feature guides at paths such as drag-and-drop/overview, drag-and-drop/reorder, drag-and-drop/drag-handle, drag-and-drop/auto-scroll, drag-and-drop/multi-select, drag-and-drop/free-form, drag-and-drop/form-builder, drag-and-drop/conditional-drop, drag-and-drop/drop-strategies and drag-and-drop/axis-lock. Each of the nine feature clips in the table links to one of those guides, so the documentation is organised around the same nine capabilities the feature list names.

Installing it, and what the version tags mean

The README does not include a code snippet for adding the dependency, so the installation route has to be read from the badges and the repository layout. The Maven Central badge names the group and artifact, com.mohamedrejeb.dnd and compose-dnd, and the build is a standard Gradle project with the wrapper scripts at the root, so adding the dependency is a coordinates entry in a Gradle build file and a version, with the project pulling from Maven Central.

The version question is the interesting part. The recent releases are v1.0.0-alpha02 from 2026-10-12, v1.0.0-alpha01 from 2026-10-11, and v0.5.0 from 2026-07-08. That is two alpha releases of a 1.0.0 in two days, and a gap of three months between the 0.5.0 line and the first alpha.

Two things follow. The first is that the API is still moving, and the 0.5.0 line and the 1.0.0 alphas are unlikely to have identical signatures, so a project pinning a version should read the CHANGELOG.md at the repository root rather than assume the current alpha matches what the documentation site describes. The second is that the alpha cadence suggests the 1.0.0 release is close, which is an argument for waiting a short while and taking a stable version rather than pinning an alpha into a production build.

The repository also has a CODE_OF_CONDUCT.md and a .github/ directory, and the build-passing badge points at the GitHub actions, so the library is built and tested in CI on every change.

Where Compose DND is the wrong choice

Three cases point elsewhere. The first is a team that needs a released, stable dependency. The library's current state is two 1.0.0 alpha tags, and a library that owns pointer gestures is one where a signature change in a modifier is a source-breaking change for every call site. A team that cannot absorb that churn should either wait for the stable 1.0.0 or use a lower-level approach.

The second is a developer who wants the library to move the data for them. The design is explicitly unidirectional in that sense: the library reports events, your state decides what changes. That is the right choice for a Compose app, where state is already the pattern, but it does mean you write the list mutation, the animation of the item to its new position, and the persistence of the new order. A drag-and-drop list for the view system would have handled that for you.

The third is a project that needs drag and drop in a non-Compose part of the app, or one where the drag is not a simple press-and-hold on a composable. The whole library is built around Compose modifiers and Compose pointer input, so there is nothing to reuse in a custom view, and gestures that need multi-touch or a modifier key have no representation in this API.

The alternative worth weighing is the drag-and-drop support in Compose Foundation itself, and the difference in approach is about scope. The Foundation library ships the primitive that a drag implementation needs, namely the drag gesture and the draggable modifier, and leaves the interaction design to you. Compose DND builds the whole layer above that: the long-press arbitration, the auto scroll at the edges, the drop target resolution when a dragged item covers several, the selection gesture, the spring animation on drop, the drag shadow. If your need is one list where a user can reorder by holding and dragging, the Foundation primitive plus a state update is a day of work. If your need is a board with columns, palettes, conditional acceptance rules and multi-axis auto scroll, Compose DND is a different order of magnitude of work, and the per-feature guides in its documentation are effectively a specification you would otherwise have to design yourself.

Editorial conclusion

Compose DND fits a Compose developer building a board, a reorderable list or a palette and who wants the same drag behaviour on Android, iOS, desktop and web from one code path, and who is willing to work against a 1.0.0 alpha API. It does not fit a team that needs a stable released version, since the newest tags are v1.0.0-alpha02 and v1.0.0-alpha01 with v0.5.0 before them, and it does not fit a developer who wants the library to own the state, because the design deliberately keeps the data in your hands. Before you adopt it, read the API for the release you are pinning, because the alpha tags and the older 0.5.0 line are unlikely to have identical signatures, and check the sample app, which is the only complete usage reference the repository points to.

Frequently asked questions

What is Compose DND?

It is a Kotlin library that lets you add drag and drop functionality to Jetpack Compose or Compose Multiplatform projects through modifiers rather than wrapper composables. The API is draggableItem, dropTarget and reorderableItem, and the library is published on Maven Central under com.mohamedrejeb.dnd with the Apache-2.0 licence.

How does Compose DND handle scrolling and taps on draggable items?

It uses long press to drag, which keeps taps and scrolling working on draggable items, and it provides auto scroll when an item is held near an edge for lazy lists, grids, staggered grids and scrollable containers, in any layout direction. The README lists working inside scrollables as a headline property of the library.

Does Compose DND keep the data or does my app?

Your app keeps the data. The library reports what happens through callbacks such as onDragStart and onDragEnd, and your state decides what changes, so you write the list mutation and the persistence of the new order yourself.

Which platforms does Compose DND support?

One API is used for every platform, with Android, iOS, desktop and web sharing the same code. The sample directory in the repository has separate modules for sample/android, sample/common, sample/desktop, sample/iosApp and sample/web.

Is Compose DND ready for production use?

The most recent tags are v1.0.0-alpha02 from 2026-10-12 and v1.0.0-alpha01 from 2026-10-11, with v0.5.0 from 2026-07-08 before them, so the 1.0.0 line is still in alpha. The project publishes a CHANGELOG.md at the repository root, and the documentation site carries a live demo and per-feature guides.

Official sources

  1. License: Apache-2.0
  2. MohamedRejeb/compose-dnd on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mohamedrejeb-compose-dnd.svg)](https://hysenlabs.com/projects/mohamedrejeb-compose-dnd)

Was this useful?