Exploring WindowDraggableArea on Compose Desktop

One of the common things you might see in a lot of popular desktop apps is, that they have a custom title bar that contains fancy toolbar icons or a search bar or some other custom view. Compose Desktop allows us to use our own title bar by just making our Window undecorated. But what if you won't make that toolbar draggable as well? Compose provides an API for that as well, which is aptly named WindowDraggableArea

The usage of it is pretty straightforward. We first start by making our Window undecorated, which allows us to use our own title bar.

Window(
  state = rememberWindowState(),
  undecorated = true,
  transparent = true,
  onCloseRequest = ::exitApplication
) {
  // content here
}

Now, we can define our fancy title bar composable and place it in the window content. To make our title bar draggable, we simply wrap it in WindowDraggableArea

Window(
  state = rememberWindowState(),
  undecorated = true,
  transparent = true,
  onCloseRequest = ::exitApplication
) {
   WindowDraggableArea {
	 AppTitleBar()
   }
}

Under the hood, WindowDraggableArea is a simple Box view that uses pointer inputs to allow us to drag our window.

@Composable
fun WindowScope.WindowDraggableArea(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit = {}
) {
    val handler = remember { DragHandler(window) }
    Box(
        modifier = modifier.pointerInput(Unit) {
            forEachGesture {
                awaitPointerEventScope {
                    awaitFirstDown()
                    handler.register()
                }
            }
        }
    ) {
        content()
    }
}

If you look at the function definition, you will also notice WindowDraggableArea is an extension of WindowScope . That means you can only use it in singleWindowApplication , Window and Dialog . If you want to use it in a different Composable, you need to pass WindowScope as a receiver.

@Composable
fun WindowScope.AppTitleBar() {
  WindowDraggableArea {
    // title bar content
  }
}

That’s it, now you can create your own custom title bar and have the option to drag it across the desktop, or have a draggable area anywhere in your app.

Gotchas

  • When you mark your window as undecorated, along with the toolbar the window frame and the elevation that is handled by the OS are also disabled/removed. So, the app will not have any elevation like other apps. Unfortunately setting elevation on your content just clips it.
  • Resizing undecorated windows is currently not supported. There is an open issue for that on the compose-jb repo.

Here is a Compose Desktop app with a custom title bar I had to implement recently.