Compose Unstyled 2.0 is out! Check the official announcement blog ->
Compose Component

TooltipBox

Material TooltipBox that wraps a composable with a tooltip.

TooltipBox social preview

PlainTooltipSample

@Preview
@Composable
fun PlainTooltipSample() {
    TooltipBox(
        positionProvider =
            TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
        tooltip = {
            PlainTooltip(
                modifier =
                    Modifier.semantics {
                        // TODO(b/496338253): Remove this modifier once bug where tooltip text is
                        //  not announced by a11y screen readers is resolved.
                        liveRegion = LiveRegionMode.Assertive
                        paneTitle = "Add to favorites"
                    }
            ) {
                Text("Add to favorites")
            }
        },
        state = rememberTooltipState(),
    ) {
        IconButton(onClick = { /* Icon button's click event */ }) {
            Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Localized Description")
        }
    }
}

PlainTooltipWithCaret

@Composable
fun PlainTooltipWithCaret() {
    TooltipBox(
        positionProvider =
            TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
        tooltip = {
            PlainTooltip(
                modifier =
                    Modifier.semantics {
                        // TODO(b/496338253): Remove this modifier once bug where tooltip text is
                        //  not announced by a11y screen readers is resolved.
                        liveRegion = LiveRegionMode.Assertive
                        paneTitle = "Add to favorites"
                    }
            ) {
                Text("Add to favorites")
            }
        },
        state = rememberTooltipState(),
    ) {
        IconButton(onClick = { /* Icon button's click event */ }) {
            Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Localized Description")
        }
    }
}

PlainTooltipWithCaretBelowAnchor

@Composable
fun PlainTooltipWithCaretBelowAnchor() {
    TooltipBox(
        positionProvider =
            TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Below),
        tooltip = {
            PlainTooltip(
                modifier =
                    Modifier.semantics {
                        // TODO(b/496338253): Remove this modifier once bug where tooltip text is
                        //  not announced by a11y screen readers is resolved.
                        liveRegion = LiveRegionMode.Assertive
                        paneTitle = "Add to favorites"
                    },
                caretShape = TooltipDefaults.caretShape(),
            ) {
                Text("Add to favorites")
            }
        },
        state = rememberTooltipState(),
    ) {
        IconButton(onClick = { /* Icon button's click event */ }) {
            Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Localized Description")
        }
    }
}

PlainTooltipWithCaretEndOfAnchor

@Composable
fun PlainTooltipWithCaretEndOfAnchor() {
    TooltipBox(
        positionProvider =
            TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.End),
        tooltip = {
            PlainTooltip(
                modifier =
                    Modifier.semantics {
                        // TODO(b/496338253): Remove this modifier once bug where tooltip text is
                        //  not announced by a11y screen readers is resolved.
                        liveRegion = LiveRegionMode.Assertive
                        paneTitle = "Add to favorites"
                    },
                caretShape = TooltipDefaults.caretShape(),
            ) {
                Text("Add to favorites")
            }
        },
        state = rememberTooltipState(),
    ) {
        IconButton(onClick = { /* Icon button's click event */ }) {
            Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Localized Description")
        }
    }
}

PlainTooltipWithCaretLeftOfAnchor

@Composable
fun PlainTooltipWithCaretLeftOfAnchor() {
    TooltipBox(
        positionProvider =
            TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Left),
        tooltip = {
            PlainTooltip(
                modifier =
                    Modifier.semantics {
                        // TODO(b/496338253): Remove this modifier once bug where tooltip text is
                        //  not announced by a11y screen readers is resolved.
                        liveRegion = LiveRegionMode.Assertive
                        paneTitle = "Add to favorites"
                    },
                caretShape = TooltipDefaults.caretShape(),
            ) {
                Text("Add to favorites")
            }
        },
        state = rememberTooltipState(),
    ) {
        IconButton(onClick = { /* Icon button's click event */ }) {
            Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Localized Description")
        }
    }
}

PlainTooltipWithCaretRightOfAnchor

@Composable
fun PlainTooltipWithCaretRightOfAnchor() {
    TooltipBox(
        positionProvider =
            TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Right),
        tooltip = {
            PlainTooltip(
                modifier =
                    Modifier.semantics {
                        // TODO(b/496338253): Remove this modifier once bug where tooltip text is
                        //  not announced by a11y screen readers is resolved.
                        liveRegion = LiveRegionMode.Assertive
                        paneTitle = "Add to favorites"
                    },
                caretShape = TooltipDefaults.caretShape(),
            ) {
                Text("Add to favorites")
            }
        },
        state = rememberTooltipState(),
    ) {
        IconButton(onClick = { /* Icon button's click event */ }) {
            Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Localized Description")
        }
    }
}

PlainTooltipWithCaretStartOfAnchor

@Composable
fun PlainTooltipWithCaretStartOfAnchor() {
    TooltipBox(
        positionProvider =
            TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Start),
        tooltip = {
            PlainTooltip(
                modifier =
                    Modifier.semantics {
                        // TODO(b/496338253): Remove this modifier once bug where tooltip text is
                        //  not announced by a11y screen readers is resolved.
                        liveRegion = LiveRegionMode.Assertive
                        paneTitle = "Add to favorites"
                    },
                caretShape = TooltipDefaults.caretShape(),
            ) {
                Text("Add to favorites")
            }
        },
        state = rememberTooltipState(),
    ) {
        IconButton(onClick = { /* Icon button's click event */ }) {
            Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Localized Description")
        }
    }
}

PlainTooltipWithCustomCaret

@Composable
fun PlainTooltipWithCustomCaret() {
    TooltipBox(
        positionProvider =
            TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
        tooltip = {
            PlainTooltip(
                modifier =
                    Modifier.semantics {
                        // TODO(b/496338253): Remove this modifier once bug where tooltip text is
                        //  not announced by a11y screen readers is resolved.
                        liveRegion = LiveRegionMode.Assertive
                        paneTitle = "Add to favorites"
                    },
                caretShape = TooltipDefaults.caretShape(DpSize(24.dp, 12.dp)),
            ) {
                Text("Add to favorites")
            }
        },
        state = rememberTooltipState(),
    ) {
        IconButton(onClick = { /* Icon button's click event */ }) {
            Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Localized Description")
        }
    }
}

PlainTooltipWithManualInvocationSample

@Preview
@Composable
fun PlainTooltipWithManualInvocationSample() {
    val tooltipState = rememberTooltipState()
    val scope = rememberCoroutineScope()
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        TooltipBox(
            positionProvider =
                TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
            tooltip = {
                PlainTooltip(
                    modifier =
                        Modifier.semantics {
                            // TODO(b/496338253): Remove this modifier once bug where tooltip text
                            // is not
                            // announced
                            //  by a11y screen readers is resolved.
                            liveRegion = LiveRegionMode.Assertive
                            paneTitle = "Add to list"
                        }
                ) {
                    Text("Add to list")
                }
            },
            state = tooltipState,
        ) {
            IconButton(onClick = { /* Icon button's click event */ }) {
                Icon(
                    imageVector = Icons.Filled.AddCircle,
                    contentDescription = "Localized Description",
                )
            }
        }
        Spacer(Modifier.requiredHeight(30.dp))
        OutlinedButton(onClick = { scope.launch { tooltipState.show() } }) {
            Text("Display tooltip")
        }
    }
}

RichTooltipSample

@Composable
fun RichTooltipSample() {
    val tooltipState = rememberTooltipState(isPersistent = true)
    val scope = rememberCoroutineScope()
    TooltipBox(
        positionProvider =
            TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
        tooltip = {
            RichTooltip(
                title = { Text(richTooltipSubheadText) },
                action = {
                    TextButton(onClick = { scope.launch { tooltipState.dismiss() } }) {
                        Text(richTooltipActionText)
                    }
                },
            ) {
                Text(richTooltipText)
            }
        },
        hasAction = true,
        state = tooltipState,
    ) {
        IconButton(onClick = { /* Icon button's click event */ }) {
            Icon(imageVector = Icons.Filled.Info, contentDescription = "Localized Description")
        }
    }
}

RichTooltipWithCaretSample

@Composable
fun RichTooltipWithCaretSample() {
    val tooltipState = rememberTooltipState(isPersistent = true)
    val scope = rememberCoroutineScope()
    TooltipBox(
        positionProvider =
            TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
        tooltip = {
            RichTooltip(
                title = { Text(richTooltipSubheadText) },
                action = {
                    TextButton(onClick = { scope.launch { tooltipState.dismiss() } }) {
                        Text(richTooltipActionText)
                    }
                },
                caretShape = TooltipDefaults.caretShape(),
            ) {
                Text(richTooltipText)
            }
        },
        hasAction = true,
        state = tooltipState,
    ) {
        IconButton(onClick = { /* Icon button's click event */ }) {
            Icon(imageVector = Icons.Filled.Info, contentDescription = "Localized Description")
        }
    }
}

RichTooltipWithCustomCaretSample

@Composable
fun RichTooltipWithCustomCaretSample() {
    val tooltipState = rememberTooltipState(isPersistent = true)
    val scope = rememberCoroutineScope()
    TooltipBox(
        positionProvider =
            TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
        tooltip = {
            RichTooltip(
                title = { Text(richTooltipSubheadText) },
                action = {
                    TextButton(onClick = { scope.launch { tooltipState.dismiss() } }) {
                        Text(richTooltipActionText)
                    }
                },
                caretShape = TooltipDefaults.caretShape(DpSize(32.dp, 16.dp)),
            ) {
                Text(richTooltipText)
            }
        },
        hasAction = true,
        state = tooltipState,
    ) {
        IconButton(onClick = { /* Icon button's click event */ }) {
            Icon(imageVector = Icons.Filled.Info, contentDescription = "Localized Description")
        }
    }
}

RichTooltipWithManualInvocationSample

@Composable
fun RichTooltipWithManualInvocationSample() {
    val tooltipState = rememberTooltipState(isPersistent = true)
    val scope = rememberCoroutineScope()
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        TooltipBox(
            positionProvider =
                TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
            tooltip = {
                RichTooltip(
                    title = { Text(richTooltipSubheadText) },
                    action = {
                        TextButton(onClick = { scope.launch { tooltipState.dismiss() } }) {
                            Text(richTooltipActionText)
                        }
                    },
                ) {
                    Text(richTooltipText)
                }
            },
            hasAction = true,
            state = tooltipState,
        ) {
            IconButton(onClick = { /* Icon button's click event */ }) {
                Icon(imageVector = Icons.Filled.Info, contentDescription = "Localized Description")
            }
        }
        Spacer(Modifier.requiredHeight(30.dp))
        OutlinedButton(onClick = { scope.launch { tooltipState.show() } }) {
            Text("Display tooltip")
        }
    }
}

Last updated: