Search code examples
kotlinfocuscompose-desktop

How to make Compose component non-focusable?


I have a Composable Row that has some click listeners:

val action = { ... }
Row(Modifier.clickable(action) {
  IconButton({ /* other, unrelated action */}) {}
  Text("This isn't clickable")
  Checkbox({ /* something that calls action() on toggle */ })
}

When tabbing through this UI, the focus goes to the IconButton, then the Checkbox, then the Row. I want it to skip the row. I've implemented that by adding to the Row modifier:

val manager = LocalFocusManager.current
Row(Modifier.clickable(action).onFocusChanged { 
  if (it.isFocused) manager.moveFocus(FocusDirection.Next) 
}) { /* same content */ }

... which works when moving forward, but not when moving backward (using Shift-Tab). And of course that's because of the FocusDirection.Next, which should instead be Previous when moving backward. But how do I detect that? The focus event doesn't have a direction property.

Update
I tried doing this by manually detecting if shift is pressed, which feels more like a hack than a solution:

val keys = LocalWindowInfo.current.keyboardModifiers
/* in onFocusChanged */
manager.moveFocus(if (keys.isShiftPressed) FocusDirection.Previous else FocusDirection.Next)

.. and also, it doesn't work. Calling manager.moveFocus(FocusDirection.Previous) if shift is pressed causes an infinite loop and application crash, presumably because it's setting the focus back to where it came from.


Solution

  • Modifier.focusProperties { canFocus = false } should help you!

    An example of usage:

    Row(Modifier.focusProperties { canFocus = false }.clickable(onClick = action)) {
      IconButton({ action() }) {
        Text("IconButton")
      }
      Text("This isn't clickable")
      Button(onClick = { action() }) {
        Text("Button")
      }
    }