Skip to content

Implement drag-to-scroll in SelectionContainer#2966

Merged
Alexander Maryanovsky (m-sasha) merged 4 commits into
jb-mainfrom
m-sasha/text-drag-scroll
Apr 14, 2026
Merged

Implement drag-to-scroll in SelectionContainer#2966
Alexander Maryanovsky (m-sasha) merged 4 commits into
jb-mainfrom
m-sasha/text-drag-scroll

Conversation

@m-sasha

@m-sasha Alexander Maryanovsky (m-sasha) commented Apr 10, 2026

Copy link
Copy Markdown

Implement scrolling the selection container when the user selects text and drags the mouse outside the text element.

Note that due to https://issuetracker.google.com/issues/343917640 the scrolling continues only as long as the mouse is moved physically. It's not enough to drag outside and wait.
Also note that this only solves the problem for non-lazy scrollable containers, e.g., Modifier.verticalScroll().

Fixes https://youtrack.jetbrains.com/issue/CMP-10039

Testing

Tested manually and added a unit test.

val LoremIpsum = """
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ipsum orci, tempus quis ex feugiat, efficitur cursus lorem. In convallis, sem ac molestie volutpat, elit nulla sodales nunc, sollicitudin feugiat turpis metus vitae mauris. Proin viverra neque odio, at vulputate nunc gravida vitae. Phasellus ac varius ante. Etiam in metus commodo, euismod felis eu, malesuada urna. Etiam quis congue nibh, sit amet dapibus est. Ut ipsum risus, hendrerit eget efficitur eu, porttitor vitae leo. Vestibulum et euismod neque. Nam tincidunt aliquam lacinia.

    In velit ligula, facilisis eu ipsum nec, mollis maximus tortor. In orci velit, iaculis vel porttitor id, condimentum eget risus. Donec congue erat ac maximus malesuada. Integer egestas bibendum lorem non dignissim. Nunc imperdiet commodo dolor, in porttitor magna dictum quis. Etiam diam augue, mattis ut felis a, semper semper risus. Nullam id rhoncus magna. Sed venenatis eget quam nec pulvinar. Suspendisse eget mollis nibh, eu maximus justo. Morbi cursus nulla massa. Quisque a tempor tortor.

    Aliquam ut aliquam erat. Vivamus non ante ipsum. Nunc rutrum turpis viverra orci efficitur, at bibendum nunc pellentesque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed laoreet mauris ut lacus maximus euismod. Nulla pharetra, neque in venenatis aliquam, sem enim congue nibh, a gravida ligula lacus malesuada felis. Pellentesque porta est ut erat mollis porta.

    Vivamus suscipit faucibus euismod. Sed vehicula lectus in tellus condimentum, mollis hendrerit enim pretium. Suspendisse potenti. Nam scelerisque mauris vitae vehicula rhoncus. Aliquam sed massa sit amet quam suscipit rutrum vitae et mi. Aenean ornare lacus magna, malesuada elementum lacus semper vulputate. Mauris tristique mauris id tristique consectetur. Sed ac nulla fringilla, pretium nisl in, placerat felis. Vestibulum venenatis mattis leo, iaculis porta tellus molestie quis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Morbi in tortor non orci suscipit scelerisque vel id justo. Nunc eu arcu condimentum, viverra lorem eget, congue arcu.

    Morbi mauris orci, sollicitudin ac ligula vestibulum, blandit pharetra justo. Mauris lobortis leo sit amet imperdiet pulvinar. Nunc posuere justo ut erat semper, et vehicula sem sodales. In sagittis fermentum purus, at tempor sapien. Integer rutrum ante ligula, at malesuada velit lobortis sit amet. Nam congue laoreet rutrum. Nullam dignissim lacinia quam, in vehicula ipsum cursus vel. Mauris imperdiet euismod lorem. Nam ut augue aliquam, hendrerit enim id, posuere urna. In id tincidunt neque.
""".trimIndent()


val HeaderStyle = SpanStyle(fontSize = 24.sp, fontWeight = FontWeight.Bold)
val ContentText = buildAnnotatedString {
    withStyle(HeaderStyle) { appendLine("Lorem Ipsum") }
    appendLine(LoremIpsum)
}

fun main() = singleWindowApplication {
    Box(
        Modifier
            .fillMaxSize()
    ) {
        val verticalScrollState = rememberScrollState()
        SelectionContainer {
            Column(Modifier.padding(16.dp).verticalScroll(verticalScrollState)) {
                repeat(10) {
                    Text(
                        text = ContentText,
                        modifier = Modifier
                    )
                }
                Box(Modifier.height(300.dp).fillMaxWidth().background(Color.Red)) {
                    Text(
                        text = "",
                        modifier = Modifier.fillMaxSize()
                    )
                }
                repeat(10) {
                    Text(
                        text = ContentText,
                        modifier = Modifier
                    )
                }
            }
        }
        VerticalScrollbar(
            rememberScrollbarAdapter(verticalScrollState), Modifier.fillMaxHeight().align(Alignment.CenterEnd),
        )
    }
}

This should be tested by QA

Release Notes

Features - Multiple Platforms

  • Implemented drag-to-scroll in SelectionContainer. When the mouse pointer is dragged outside the element while selecting text, the text element will be scrolled accordingly. Note that this requires wrapping the content in a scrolling modifier, e.g. Modifier.verticalScroll.

@m-sasha

Alexander Maryanovsky (m-sasha) commented Apr 10, 2026

Copy link
Copy Markdown
Author

Vendula Švastalová (@svastven) Adding you to the PR because I also changed the implementation in SelectionController.ios.kt, hopefully preserving the behavior there.

The reason I needed to change it is that bringIntoView requires a coroutine scope, which was not previously available to the mouseSelectionObserver.

@@ -23,4 +23,4 @@ import androidx.compose.ui.layout.LayoutCoordinates
internal actual fun SelectionRegistrar.makeSelectionModifier(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://issuetracker.google.com/issues/343917640

If we decide that we should implement it via synthetic events (see another comment), we can ask increasing priority of this, or upstream a fix.

In the context of this issue it looks important in my opinion - the feature looks half-baked without it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide that we should implement it via synthetic events (see another comment), we can ask increasing priority of this, or upstream a fix.

I'm already discussing it with Googlers

In the context of this issue it looks important in my opinion - the feature looks half-baked without it.

I agree, but note that this is how it currently works in text fields, for example.

@@ -23,4 +23,4 @@ import androidx.compose.ui.layout.LayoutCoordinates
internal actual fun SelectionRegistrar.makeSelectionModifier(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, create a follow-up task (or don't close existing one) to support it for touch. It doesn't look like Mouse-specific feature (I checked my Android phone - it works in Chrome, but it is buggy)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm working on this with Google.

It's more difficult for touch, but more critical for mouse...

@igordmn Igor Demin (igordmn) Apr 13, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, don't close the original tasks or create a new one to have it tracked

@@ -23,4 +23,4 @@ import androidx.compose.ui.layout.LayoutCoordinates
internal actual fun SelectionRegistrar.makeSelectionModifier(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, create a follow-up task (or don't close existing one) to support it for Android, to have the same features during cross-platform development. In YouTrack, to keep it tracked. And optionally in the Google tracker if we are ready to engage in the discussion.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc Ivan Matkov (@MatkovIvan) for extending the behavior on CMP platforms comparing to AOSP/Android

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@igordmn Igor Demin (igordmn) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to merge, but to be safe, the iOS part needs to be checked. Just looking at it - the code looks correct.

We can check it after merging if we need it merged sooner.

@m-sasha

Copy link
Copy Markdown
Author

Vendula Švastalová (@svastven) can you check & approve?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me it looks good. Just two small related comments.

@m-sasha Alexander Maryanovsky (m-sasha) merged commit 64e4bc5 into jb-main Apr 14, 2026
47 of 48 checks passed
@m-sasha Alexander Maryanovsky (m-sasha) deleted the m-sasha/text-drag-scroll branch April 14, 2026 06:15
Vlad Konstantinov (Kpotko) added a commit that referenced this pull request Apr 14, 2026
Implement scrolling the selection container when the user selects text
and drags the mouse outside the text element.

This is a cherry-pick of
#2966

## Testing
N/A

## Release Notes
### Features - Multiple Platforms
- Implemented drag-to-scroll in `SelectionContainer`. When the mouse
pointer is dragged outside the element while selecting text, the text
element will be scrolled accordingly. Note that this requires wrapping
the content in a scrolling container/modifier, e.g.
`Modifier.verticalScroll`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants