Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jetpack Compose TextToolbar not showing for TextField in ModalBottomSheet

In Jetpack Compose I have a TextField in a Surface and it displays the TextToolbar (just for a Paste) without issues. If I put the same TextField into a (material3) ModalBottomSheet I do not see that toolbar? How can I show the toolbar for a ModalBottomSheet? What is causing the toolbar to stay hidden?

I've created a minimal demo here for others to reproduce the issue. All the important stuff is in the MainActivity here.

enter image description here

enter image description here

like image 638
Oliver Metz Avatar asked Oct 25 '25 07:10

Oliver Metz


1 Answers

Jetpack Compose is still a relatively new framework, and as such, some features are not supported yet. As far as I know, the TextToolbar is not supported to be used inside a ModalBottomSheet(Google Issue Tracker). This is because the ModalBottomSheet takes up the entire screen, and the TextToolbar is not positioned correctly in this context.
If you need a toolbar for your bottom sheet, I think you have two options :
1. Use a trailing Past icon with textField(easy way that works fine)
2. Create a custom toolbar component that is specifically designed to be used in ModalBottomSheet

Implementing the second way could be a little complex. I tried to implement this method in general.
This is a summary of what my code does:
1. I made a new composable specifically for using inside modal (TextFieldWithCustomToolBar)
2. The new composable has a TextFild and a DropdownMenu which will act instead of native toolbar
3. We need to detect long press on TextFild, Jetpack Compose has modifiers for handling various gestures, including drag, click, and scroll, but it doesn't work directly on text fields. This is because text fields have their own built-in gesture-handling system that intercepts user interactions before they reach the pointer input modifier. So I did it manually by collecting information from interactionSource

@Composable
fun TextFieldWithCustomToolBar(
    supportingText: String,
    onPasteRequested: () -> Unit
) {

    var expanded by remember {
        mutableStateOf(false)
    }
    val text = remember { mutableStateOf("") }
    val interactionSource = remember { MutableInteractionSource() }
    val viewConfiguration = LocalViewConfiguration.current

    //wait for a long press action
    LaunchedEffect(interactionSource) {
        var isDown = false
        interactionSource.interactions.collect { interaction ->
            when (interaction) {
                is PressInteraction.Press -> {
                    isDown = true
                    CoroutineScope(Dispatchers.Main).launch {
                        delay(viewConfiguration.longPressTimeoutMillis)
                        if (isDown) expanded = true
                    }
                }

                is PressInteraction.Release -> {
                    isDown = false
                }
            }
        }
    }
    Box {
        TextField(
            interactionSource = interactionSource,
            value = text.value,
            onValueChange = { text.value = it },
            supportingText = { Text(text = supportingText) }
        )

        DropdownMenu(
            expanded = expanded,
            properties = PopupProperties(focusable = false),
            onDismissRequest = { expanded = false },
        ) {
            DropdownMenuItem({ Text(text = "Paste") }, onClick = {
                expanded = false
                onPasteRequested.invoke()
            })
        }
    }
}

🔴 If the popup padding is a problem for you, check this answer

like image 121
ucMedia Avatar answered Oct 26 '25 22:10

ucMedia



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!