{"slug":"tooltip","title":"Tooltip","description":"Using the tooltip machine in your project.","contentType":"component","framework":"vue","content":"A tooltip is a brief, informative message that appears when a user interacts\nwith an element. Tooltips are usually initiated when a button is focused or\nhovered.\n\n## Resources\n\n\n[Latest version: v1.39.1](https://www.npmjs.com/package/@zag-js/tooltip)\n[Logic Visualizer](https://zag-visualizer.vercel.app/tooltip)\n[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/tooltip)\n\n\n\n**Features**\n\n- Show tooltip on hover and focus\n- Hide tooltip on Esc, click, pointer down, or scroll\n- Only one tooltip shows at a time\n- Labeling support for screen readers via `aria-describedby`\n- Custom show and hide delay support\n- Matches native tooltip behavior with delay on hover of first tooltip and no\n  delay on subsequent tooltips\n- Supports multiple triggers sharing a single tooltip instance\n\n## Installation\n\nInstall the tooltip package:\n\n```bash\nnpm install @zag-js/tooltip @zag-js/vue\n# or\nyarn add @zag-js/tooltip @zag-js/vue\n```\n\n## Anatomy\n\nCheck the tooltip anatomy and part names.\n\n> Each part includes a `data-part` attribute to help identify them in the DOM.\n\n\n\n## Usage\n\nImport the tooltip package:\n\n```tsx\nimport * as tooltip from \"@zag-js/tooltip\"\n```\n\nThe tooltip package exports two key functions:\n\n- `machine` - State machine logic.\n- `connect` - Maps machine state to JSX props and event handlers.\n\nTo get tooltip working, you'll need to:\n\n- Set up the tooltip portal (shared container for tooltips)\n- Add `triggerProps` and `tooltipProps` to the right elements\n\nThen use the framework integration helpers:\n\n```html\n<script setup>\n  import * as tooltip from \"@zag-js/tooltip\"\n  import { normalizeProps, useMachine } from \"@zag-js/vue\"\n  import { computed } from \"vue\"\n\n  const service = useMachine(tooltip.machine, { id: \"1\" })\n  const api = computed(() => tooltip.connect(service, normalizeProps))\n</script>\n\n<template>\n  <div>\n    <button ref=\"ref\" v-bind=\"api.getTriggerProps()\">Hover me</button>\n    <div v-if=\"api.open\" v-bind=\"api.getPositionerProps()\">\n      <div v-bind=\"api.getContentProps()\">Tooltip</div>\n    </div>\n  </div>\n</template>\n```\n\n### Customizing the timings\n\nBy default, the tooltip opens after `400ms` and closes after `150ms`. You can\ncustomize this by passing the `openDelay` and `closeDelay` context properties.\n\n```tsx {2-3}\nconst service = useMachine(tooltip.machine, {\n  openDelay: 500,\n  closeDelay: 200,\n})\n```\n\n### Changing the placement\n\nThe tooltip uses [floating-ui](https://floating-ui.com/) for dynamic\npositioning. You can change the placement of the tooltip by passing the\n`positioning.placement` context property to the machine.\n\n```tsx {2-4}\nconst service = useMachine(tooltip.machine, {\n  positioning: {\n    placement: \"bottom-start\",\n  },\n})\n```\n\n### Adding an arrow\n\nTo render an arrow within the tooltip, use the `api.getArrowProps()` and\n`api.getArrowTipProps()`.\n\n```tsx {6-8}\n//...\nconst api = tooltip.connect(service, normalizeProps)\n//...\nreturn (\n  <div {...api.getPositionerProps()}>\n    <div {...api.getArrowProps()}>\n      <div {...api.getArrowTipProps()} />\n    </div>\n    <div {...api.getContentProps()}>{/* ... */}</div>\n  </div>\n)\n//...\n```\n\n### Dismiss behavior\n\nTooltips close on Escape, click, pointer down, and scroll by default. Configure\nthese with `closeOnEscape`, `closeOnClick`, `closeOnPointerDown`, and\n`closeOnScroll`.\n\n```tsx {2-5}\nconst service = useMachine(tooltip.machine, {\n  closeOnEscape: false,\n  closeOnClick: false,\n  closeOnPointerDown: false,\n  closeOnScroll: false,\n})\n```\n\n### Making the tooltip interactive\n\nSet the `interactive` context property to `true` to make the tooltip\ninteractive.\n\nWhen a tooltip is interactive, it remains open as the pointer moves from the\ntrigger into the content.\n\n```tsx {2}\nconst service = useMachine(tooltip.machine, {\n  interactive: true,\n})\n```\n\n### Listening for open state changes\n\nWhen the tooltip is opened or closed, the `onOpenChange` callback is invoked.\n\n```tsx {2-7}\nconst service = useMachine(tooltip.machine, {\n  onOpenChange(details) {\n    // details => { open: boolean }\n    console.log(details.open)\n  },\n})\n```\n\n### Multiple triggers\n\nA single tooltip instance can be shared across multiple trigger elements. Pass a\n`value` to `getTriggerProps` to identify each trigger.\n\n```tsx\nconst service = useMachine(tooltip.machine, {\n  onTriggerValueChange({ value }) {\n    console.log(\"active trigger:\", value)\n  },\n})\n\nconst api = tooltip.connect(service, normalizeProps)\n\nreturn (\n  <>\n    <button {...api.getTriggerProps({ value: \"bold\" })}>B</button>\n    <button {...api.getTriggerProps({ value: \"italic\" })}>I</button>\n    <div {...api.getPositionerProps()}>\n      <div {...api.getContentProps()}>\n        {api.triggerValue === \"bold\" ? \"Bold\" : \"Italic\"}\n      </div>\n    </div>\n  </>\n)\n```\n\nWhen hovering a different trigger while the tooltip is open, it repositions\nwithout closing. `aria-describedby` is scoped to the active trigger.\n\n### Controlled tooltip\n\nUse `open` and `onOpenChange` for controlled usage.\n\n```tsx\nconst service = useMachine(tooltip.machine, {\n  open,\n  onOpenChange(details) {\n    setOpen(details.open)\n  },\n})\n```\n\n### Programmatic open\n\nUse the connected API for imperative control.\n\n```tsx\napi.setOpen(true)\n```\n\n## Styling guide\n\nEach part includes a `data-part` attribute you can target in CSS.\n\n```css\n[data-part=\"trigger\"] {\n  /* styles for the content */\n}\n\n[data-part=\"content\"] {\n  /* styles for the content */\n}\n```\n\n### Open and close states\n\nWhen the tooltip is open, the `data-state` attribute is added to the trigger\n\n```css\n[data-part=\"trigger\"][data-state=\"open|closed\"] {\n  /* styles for the trigger's expanded state */\n}\n\n[data-part=\"content\"][data-state=\"open|closed\"] {\n  /* styles for the trigger's expanded state */\n}\n```\n\n### Styling the arrow\n\nWhen using arrows within the menu, you can style it using css variables.\n\n```css\n[data-part=\"arrow\"] {\n  --arrow-size: 20px;\n  --arrow-background: red;\n}\n```\n\n## Methods and Properties\n\n### Machine Context\n\nThe tooltip machine exposes the following context properties:\n\n**`ids`**\nType: `Partial<{ trigger: string | ((value?: string) => string); content: string; arrow: string; positioner: string; }>`\nDescription: The ids of the elements in the tooltip. Useful for composition.\n\n**`openDelay`**\nType: `number`\nDescription: The open delay of the tooltip.\n\n**`closeDelay`**\nType: `number`\nDescription: The close delay of the tooltip.\n\n**`closeOnPointerDown`**\nType: `boolean`\nDescription: Whether to close the tooltip on pointerdown.\n\n**`closeOnEscape`**\nType: `boolean`\nDescription: Whether to close the tooltip when the Escape key is pressed.\n\n**`closeOnScroll`**\nType: `boolean`\nDescription: Whether the tooltip should close on scroll\n\n**`closeOnClick`**\nType: `boolean`\nDescription: Whether the tooltip should close on click\n\n**`interactive`**\nType: `boolean`\nDescription: Whether the tooltip's content is interactive.\nIn this mode, the tooltip will remain open when user hovers over the content.\n\n**`onOpenChange`**\nType: `(details: OpenChangeDetails) => void`\nDescription: Function called when the tooltip is opened.\n\n**`aria-label`**\nType: `string`\nDescription: Custom label for the tooltip.\n\n**`positioning`**\nType: `PositioningOptions`\nDescription: The user provided options used to position the popover content\n\n**`disabled`**\nType: `boolean`\nDescription: Whether the tooltip is disabled\n\n**`open`**\nType: `boolean`\nDescription: The controlled open state of the tooltip\n\n**`defaultOpen`**\nType: `boolean`\nDescription: The initial open state of the tooltip when rendered.\nUse when you don't need to control the open state of the tooltip.\n\n**`triggerValue`**\nType: `string`\nDescription: The controlled trigger value\n\n**`defaultTriggerValue`**\nType: `string`\nDescription: The initial trigger value when rendered.\nUse when you don't need to control the trigger value.\n\n**`onTriggerValueChange`**\nType: `(details: TriggerValueChangeDetails) => void`\nDescription: Function called when the trigger value changes.\n\n**`dir`**\nType: `\"ltr\" | \"rtl\"`\nDescription: The document's text/writing direction.\n\n**`id`**\nType: `string`\nDescription: The unique identifier of the machine.\n\n**`getRootNode`**\nType: `() => ShadowRoot | Node | Document`\nDescription: A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.\n\n### Machine API\n\nThe tooltip `api` exposes the following methods:\n\n**`open`**\nType: `boolean`\nDescription: Whether the tooltip is open.\n\n**`setOpen`**\nType: `(open: boolean) => void`\nDescription: Function to open the tooltip.\n\n**`triggerValue`**\nType: `string`\nDescription: The trigger value\n\n**`setTriggerValue`**\nType: `(value: string) => void`\nDescription: Function to set the trigger value\n\n**`reposition`**\nType: `(options?: Partial<PositioningOptions>) => void`\nDescription: Function to reposition the popover\n\n### Data Attributes\n\n**`Trigger`**\n\n**`data-scope`**: tooltip\n**`data-part`**: trigger\n**`data-value`**: The value of the item\n**`data-current`**: Present when current\n**`data-expanded`**: Present when expanded\n**`data-state`**: \"open\" | \"closed\"\n\n**`Content`**\n\n**`data-scope`**: tooltip\n**`data-part`**: content\n**`data-state`**: \"open\" | \"closed\"\n**`data-instant`**: \n**`data-placement`**: The placement of the content\n\n### CSS Variables\n\n<CssVarTable name=\"tooltip\" />\n\n## Accessibility\n\n### Keyboard Interactions\n\n**`Tab`**\nDescription: Opens/closes the tooltip without delay.\n\n**`Escape`**\nDescription: If open, closes the tooltip without delay.","package":"@zag-js/tooltip","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/components/tooltip.mdx"}