Enable user interactions

Jetpack Compose enables fine-grained interactivity in Text. Text selection is now more flexible and can be done across composable layouts. User interactions in text are different from other composable layouts, as you can’t add a modifier to a portion of a Text composable. This page highlights the APIs that enable user interactions.

Select text

By default, composables aren’t selectable, which means that users can't select and copy text from your app. To enable text selection, wrap your text elements with a SelectionContainer composable:

@Composable
fun SelectableText() {
    SelectionContainer {
        Text("This text is selectable")
    }
}

A short passage of text, selected by the user.

You may want to disable selection on specific parts of a selectable area. To do so, you need to wrap the unselectable part with a DisableSelection composable:

@Composable
fun PartiallySelectableText() {
    SelectionContainer {
        Column {
            Text("This text is selectable")
            Text("This one too")
            Text("This one as well")
            DisableSelection {
                Text("But not this one")
                Text("Neither this one")
            }
            Text("But again, you can select this one")
            Text("And this one too")
        }
    }
}

A longer passage of text. The user tried to select the whole passage, but since two lines had DisableSelection applied, they were not selected.

Get position of a click on text

To listen for clicks on Text, you can add the clickable modifier. However, if you want to get the position of a click within a Text composable, in the case where you have different actions based on different parts of the text, you need to use a ClickableText instead:

@Composable
fun SimpleClickableText() {
    ClickableText(text = AnnotatedString("Click Me"), onClick = { offset ->
        Log.d("ClickableText", "$offset -th character is clicked.")
    })
}

Click with annotation

When a user clicks on a Text composable, you may want to attach extra information to a part of the Text value, like a URL attached to a specific word to be opened in a browser for example. To do so, you need to attach an annotation, which takes a tag (String), an item (String), and a text range as parameters. From an AnnotatedString, these annotations can be filtered with their tags or text ranges. Here’s an example:

@Composable
fun AnnotatedClickableText() {
    val annotatedText = buildAnnotatedString {
        append("Click ")

        // We attach this *URL* annotation to the following content
        // until `pop()` is called
        pushStringAnnotation(
            tag = "URL", annotation = "https://developer.android.com"
        )
        withStyle(
            style = SpanStyle(
                color = Color.Blue, fontWeight = FontWeight.Bold
            )
        ) {
            append("here")
        }

        pop()
    }

    ClickableText(text = annotatedText, onClick = { offset ->
        // We check if there is an *URL* annotation attached to the text
        // at the clicked position
        annotatedText.getStringAnnotations(
            tag = "URL", start = offset, end = offset
        ).firstOrNull()?.let { annotation ->
            // If yes, we log its value
            Log.d("Clicked URL", annotation.item)
        }
    })
}