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