import com.composeunstyled.Tooltip
import com.composeunstyled.TooltipPanel
@Composable
fun ArrowUp(modifier: Modifier = Modifier, color: Color) {
    Canvas(modifier = modifier.size(8.dp, 4.dp)) {
        val path = Path().apply {
            moveTo(size.width / 2f, 0f)
            lineTo(0f, size.height)
            lineTo(size.width, size.height)
            close()
        }
        drawPath(path, color = color)
    }
}

@Composable
fun TooltipExample() {
    Tooltip(
        placement = RelativeAlignment.TopCenter,
        panel = {
            TooltipPanel(
                modifier = Modifier.zIndex(15f),
                arrow = { direction ->
                    // Draw your arrow pointing towards the given direction
                    val degrees = when (direction) {
                        TooltipArrowDirection.Up -> 0f
                        TooltipArrowDirection.Down -> 180f
                        TooltipArrowDirection.Left -> 90f
                        TooltipArrowDirection.Right -> 270f
                    }
                    ArrowUp(Modifier.rotate(degrees), Color.Black.copy(0.8f))
                }
            ) {
                Text("This is a tooltip")
            }
        }
    ) {
        Button(onClick = {}) {
            Text("Hover me")
        }
    }
}

Basic Example

The Tooltip component has 2 main slots: its panel and its anchor.

The anchor contains the element to which the tooltip is anchored. When this element has focus, is hovered or long-pressed (on touch) the tooltip will be displayed.

The panel contains one of the overloads of TooltipPanel which renders the content of the tooltip according to the Tooltip's internal state.

Tooltips are placed in the same layout as the trigger. This is different to how Tooltips work in Compose Foundation, in order to prevent any focus and pointer issues. Because of this, you need to use Modifier.zIndex() to your panel to place it above other elements in the same layout.

Tooltip(
    placement = RelativeAlignment.TopCenter,
    panel = {
        TooltipPanel(
            modifier = Modifier.zIndex(15f),
            enter = slideInVertically(tween(150), initialOffsetY = { (it * 0.25).toInt() }) +
                    scaleIn(
                        animationSpec = tween(150),
                        transformOrigin = TransformOrigin(0.5f, 1f),
                        initialScale = 0.65f
                    ) + fadeIn(tween(150)),
            exit = fadeOut(tween(250)),
            arrow = { direction ->
                val degrees = when (direction) {
                    TooltipArrowDirection.Up -> 0f
                    TooltipArrowDirection.Down -> 180f
                    TooltipArrowDirection.Left -> 90f
                    TooltipArrowDirection.Right -> 270f
                }
                ArrowUp(Modifier.rotate(degrees), Color.Black.copy(0.8f))
            }
        ) {
            Box(
                modifier = Modifier
                    .clip(RoundedCornerShape(100))
                    .background(Color.Black.copy(0.8f))
                    .padding(vertical = 8.dp, horizontal = 12.dp),
            ) {
                Text("Notifications", color = Color.White)
            }
        }
    }
) {
    val interactionSource = remember { MutableInteractionSource() }

    Button(
        onClick = { },
        contentPadding = PaddingValues(8.dp),
        shape = CircleShape,
        modifier = Modifier.focusRing(interactionSource, 1.dp, Color(0xFF3B82F6), CircleShape),
        interactionSource = interactionSource
    ) {
        Icon(Lucide.BellDot, contentDescription = null)
    }
}

Code Examples

Styling the Tooltip

The TooltipPanel composable contains styling properties such as backgroundColor, contentColor, shape and contentPadding for easy styling.

Tooltip(
    placement = RelativeAlignment.TopCenter,
    panel = {
        TooltipPanel(
            modifier = Modifier.zIndex(15f),
            backgroundColor = Color(0xFF1E293B),
            contentColor = Color.White,
            shape = RoundedCornerShape(8.dp),
            contentPadding = PaddingValues(horizontal = 12.dp, vertical = 8.dp)
        ) {
            Text("Styled tooltip")
        }
    }
) {
    Button(onClick = {}) {
        Text("Hover me")
    }
}

Positioning the Tooltip

Pass the relative alignment you want to the Tooltip's placement property:

Tooltip(
    placement = RelativeAlignment.TopEnd,
    panel = {
        TooltipPanel {
            Text("This is a tooltip")
        }
    }
) {
    Button(onClick = {}) {
        Text("Hover me")
    }
}

Tooltip with Arrow (Caret)

Use the TooltipPanel with the arrow parameter. The arrow lambda gives you the TooltipArrowDirection which the arrow needs to be pointing towards.

We will always place the arrow between the anchor and the panel centering it to the respective direction.

@Composable
fun ArrowUp(modifier: Modifier = Modifier, color: Color) {
    Canvas(modifier = modifier.size(8.dp, 4.dp)) {
        val path = Path().apply {
            moveTo(size.width / 2f, 0f)
            lineTo(0f, size.height)
            lineTo(size.width, size.height)
            close()
        }
        drawPath(path, color = color)
    }
}

Tooltip(
    placement = RelativeAlignment.BottomCenter,
    panel = {
        TooltipPanel(
            modifier = Modifier.zIndex(15f),
            arrow = { direction ->
                // Draw your arrow pointing towards the given direction
                val degrees = when (direction) {
                    TooltipArrowDirection.Up -> 0f
                    TooltipArrowDirection.Down -> 180f
                    TooltipArrowDirection.Left -> 90f
                    TooltipArrowDirection.Right -> 270f
                }
                ArrowUp(Modifier.rotate(degrees), Color.Black)
            }
        ) {
            Text("Tooltip with arrow")
        }
    }
) {
    Button(onClick = {}) {
        Text("Hover me")
    }
}

Animating the Tooltip

Pass the respective animation specs you want in the TooltipPanel's enter and exit parameters:

Tooltip(
    placement = RelativeAlignment.TopCenter,
    panel = {
        TooltipPanel(
            modifier = Modifier.zIndex(15f),
            enter = fadeIn(animationSpec = tween(300)),
            exit = fadeOut(animationSpec = tween(300))
        ) {
            Text("This tooltip fades in and out")
        }
    }
) {
    Button(onClick = {}) {
        Text("Hover me")
    }
}

Unstyled Tooltip vs Compose Foundation Tooltips

Tooltips in Compose Foundation are implemented using Popups. Popups do not allow pointer events behind them. This can cause weird glitches when the Tooltip is right above the trigger and mouse overed.

Unstyled Tooltips are placed in the same layout as its trigger, and do not use Popups. As a result, there are no weird focus or pointer issues.

Keyboard Interactions

Key Description
Escape
Dismisses the tooltip when it is visible.

Component API

Tooltip

Parameter Description
enabled Whether the tooltip is enabled. When disabled, the tooltip will not show.
panel A composable function that defines the tooltip content panel.
placement The relative alignment of the tooltip to the anchor element. Default is TopCenter.
longPressShowDurationMillis Duration in milliseconds to show the tooltip after a long press. Default is 1500ms.
hoverDelayMillis Delay in milliseconds before showing the tooltip on hover. Default is 0ms.
anchor A composable function that defines the anchor element that triggers the tooltip.

TooltipPanel

Parameter Description
modifier Modifier to be applied to the tooltip panel.
enter The enter transition for the tooltip panel. Default is instant appearance.
exit The exit transition for the tooltip panel. Default is instant disappearance.
shape The shape of the tooltip panel.
backgroundColor The background color of the tooltip panel.
contentColor The color to apply to the contents of the tooltip panel.
contentPadding Padding values for the content within the tooltip panel.
content A composable function that defines the content of the tooltip.

TooltipPanel (with arrow)

Parameter Description
modifier Modifier to be applied to the tooltip panel.
arrow A composable function that receives TooltipArrowDirection and draws the arrow accordingly.
enter The enter transition for the tooltip panel. Default is instant appearance.
exit The exit transition for the tooltip panel. Default is instant disappearance.
content A composable function that defines the content of the tooltip.