Skip to main content

A tooltip is a brief, informative message that appears when a user interacts with an element. Tooltips are usually initiated when a button is focused or hovered.

Loading...

Features

  • Show tooltip on hover and focus
  • Hide tooltip on Esc, click, pointer down, or scroll
  • Only one tooltip shows at a time
  • Labeling support for screen readers via aria-describedby
  • Custom show and hide delay support
  • Matches native tooltip behavior with delay on hover of first tooltip and no delay on subsequent tooltips

Installation

Install the tooltip package:

npm install @zag-js/tooltip @zag-js/vue # or yarn add @zag-js/tooltip @zag-js/vue

Anatomy

Check the tooltip anatomy and part names.

Each part includes a data-part attribute to help identify them in the DOM.

Usage

Import the tooltip package:

import * as tooltip from "@zag-js/tooltip"

The tooltip package exports two key functions:

  • machine - State machine logic.
  • connect - Maps machine state to JSX props and event handlers.

To get tooltip working, you'll need to:

  • Set up the tooltip portal (shared container for tooltips)
  • Add triggerProps and tooltipProps to the right elements

Then use the framework integration helpers:

<script setup> import * as tooltip from "@zag-js/tooltip" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" const service = useMachine(tooltip.machine, { id: "1" }) const api = computed(() => tooltip.connect(service, normalizeProps)) </script> <template> <div> <button ref="ref" v-bind="api.getTriggerProps()">Hover me</button> <div v-if="api.open" v-bind="api.getPositionerProps()"> <div v-bind="api.getContentProps()">Tooltip</div> </div> </div> </template>

Customizing the timings

By default, the tooltip opens after 400ms and closes after 150ms. You can customize this by passing the openDelay and closeDelay context properties.

const service = useMachine(tooltip.machine, { openDelay: 500, closeDelay: 200, })

Changing the placement

The tooltip uses floating-ui for dynamic positioning. You can change the placement of the tooltip by passing the positioning.placement context property to the machine.

const service = useMachine(tooltip.machine, { positioning: { placement: "bottom-start", }, })

Adding an arrow

To render an arrow within the tooltip, use the api.getArrowProps() and api.getArrowTipProps().

//... const api = tooltip.connect(service, normalizeProps) //... return ( <div {...api.getPositionerProps()}> <div {...api.getArrowProps()}> <div {...api.getArrowTipProps()} /> </div> <div {...api.getContentProps()}>{/* ... */}</div> </div> ) //...

Dismiss behavior

Tooltips close on Escape, click, pointer down, and scroll by default. Configure these with closeOnEscape, closeOnClick, closeOnPointerDown, and closeOnScroll.

const service = useMachine(tooltip.machine, { closeOnEscape: false, closeOnClick: false, closeOnPointerDown: false, closeOnScroll: false, })

Making the tooltip interactive

Set the interactive context property to true to make the tooltip interactive.

When a tooltip is interactive, it remains open as the pointer moves from the trigger into the content.

const service = useMachine(tooltip.machine, { interactive: true, })

Listening for open state changes

When the tooltip is opened or closed, the onOpenChange callback is invoked.

const service = useMachine(tooltip.machine, { onOpenChange(details) { // details => { open: boolean } console.log(details.open) }, })

Controlled tooltip

Use open and onOpenChange for controlled usage.

const service = useMachine(tooltip.machine, { open, onOpenChange(details) { setOpen(details.open) }, })

Programmatic open

Use the connected API for imperative control.

api.setOpen(true)

Styling guide

Each part includes a data-part attribute you can target in CSS.

[data-part="trigger"] { /* styles for the content */ } [data-part="content"] { /* styles for the content */ }

Open and close states

When the tooltip is open, the data-state attribute is added to the trigger

[data-part="trigger"][data-state="open|closed"] { /* styles for the trigger's expanded state */ } [data-part="content"][data-state="open|closed"] { /* styles for the trigger's expanded state */ }

Styling the arrow

When using arrows within the menu, you can style it using css variables.

[data-part="arrow"] { --arrow-size: 20px; --arrow-background: red; }

Methods and Properties

Machine Context

The tooltip machine exposes the following context properties:

  • idsPartial<{ trigger: string; content: string; arrow: string; positioner: string; }>The ids of the elements in the tooltip. Useful for composition.
  • openDelaynumberThe open delay of the tooltip.
  • closeDelaynumberThe close delay of the tooltip.
  • closeOnPointerDownbooleanWhether to close the tooltip on pointerdown.
  • closeOnEscapebooleanWhether to close the tooltip when the Escape key is pressed.
  • closeOnScrollbooleanWhether the tooltip should close on scroll
  • closeOnClickbooleanWhether the tooltip should close on click
  • interactivebooleanWhether the tooltip's content is interactive. In this mode, the tooltip will remain open when user hovers over the content.
  • onOpenChange(details: OpenChangeDetails) => voidFunction called when the tooltip is opened.
  • aria-labelstringCustom label for the tooltip.
  • positioningPositioningOptionsThe user provided options used to position the popover content
  • disabledbooleanWhether the tooltip is disabled
  • openbooleanThe controlled open state of the tooltip
  • defaultOpenbooleanThe initial open state of the tooltip when rendered. Use when you don't need to control the open state of the tooltip.
  • dir"ltr" | "rtl"The document's text/writing direction.
  • idstringThe unique identifier of the machine.
  • getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

Machine API

The tooltip api exposes the following methods:

  • openbooleanWhether the tooltip is open.
  • setOpen(open: boolean) => voidFunction to open the tooltip.
  • reposition(options?: Partial<PositioningOptions>) => voidFunction to reposition the popover

Data Attributes

Trigger
data-scope
tooltip
data-part
trigger
data-expanded
Present when expanded
data-state
"open" | "closed"
Content
data-scope
tooltip
data-part
content
data-state
"open" | "closed"
data-placement
The placement of the content

CSS Variables

Arrow
--arrow-size
The size of the arrow
--arrow-size-half
Half the size of the arrow
--arrow-background
Use this variable to style the arrow background
--arrow-offset
The offset position of the arrow
Positioner
--reference-width
The width of the reference element
--reference-height
The height of the root
--available-width
The available width in viewport
--available-height
The available height in viewport
--x
The x position for transform
--y
The y position for transform
--z-index
The z-index value
--transform-origin
The transform origin for animations

Accessibility

Keyboard Interactions

  • Tab
    Opens/closes the tooltip without delay.
  • Escape
    If open, closes the tooltip without delay.
Edit this page on GitHub