---
title: Tooltip
description: A non-interactive popup component that displays contextual information when an element is focused, hovered, or long-pressed. Comes with tons of customization options such as animation support, arrow (caret) support and handle screen reader announcements out of the box.
---

```compose id="tooltip-demo" height=200
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.slideInVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import com.composeunstyled.Button
import com.composeunstyled.RelativeAlignment
import com.composeunstyled.Text
import com.composeunstyled.Tooltip
import com.composeunstyled.TooltipArrowDirection
import com.composeunstyled.TooltipPanel
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.Canvas
import androidx.compose.ui.graphics.Path

COMPOSE {
    @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.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("This is a tooltip", color = Color.White)
                }
            }
        }
    ) {
        Button(
            onClick = { },
            contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
            backgroundColor = Color.White,
            shape = RoundedCornerShape(8.dp),
            modifier = Modifier.border(1.dp, Color(0xFFE5E7EB), RoundedCornerShape(8.dp))
        ) {
            Text("Hover me")
        }
    }
}
```

```kotlin
import com.composeunstyled.Tooltip
import com.composeunstyled.TooltipPanel
```

```kotlin
@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](#unstyled-tooltip-vs-compose-foundation-tooltips), 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.

```kotlin
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.

```kotlin
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:

```kotlin
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.

```kotlin
@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:

```kotlin
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                               |
|----------------------------------------|-------------------------------------------|
| <div class="keyboard-key">Escape</div> | 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.                               |

