{"slug":"tooltip","title":"Tooltip","description":"Using the tooltip machine in your project.","contentType":"component","framework":"react","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.31.0](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 or pointer down\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\n## Installation\n\nTo use the tooltip machine in your project, run the following command in your\ncommand line:\n\n```bash\nnpm install @zag-js/tooltip @zag-js/react\n# or\nyarn add @zag-js/tooltip @zag-js/react\n```\n\n## Anatomy\n\nTo set up the tooltip correctly, you'll need to understand its anatomy and how\nwe name its parts.\n\n> Each part includes a `data-part` attribute to help identify them in the DOM.\n\n\n\n## Usage\n\nFirst, import the tooltip package into your project\n\n```jsx\nimport * as tooltip from \"@zag-js/tooltip\"\n```\n\nThe tooltip package exports two key functions:\n\n- `machine` — The state machine logic for the tooltip widget.\n- `connect` — The function that translates the machine's state to JSX attributes\n  and event handlers.\n\nTo get the tooltip working correct, you'll need to:\n\n- Setup the tooltip portal, this is a shared container for all tooltips\n- Add the `triggerProps`, and `tooltipProps` to the elements\n\n> You'll also need to provide a unique `id` to the `useMachine` hook. This is\n> used to ensure that every part has a unique identifier.\n\nNext, import the required hooks and functions for your framework and use the\ntooltip machine in your project 🔥\n\n```jsx\nimport * as tooltip from \"@zag-js/tooltip\"\nimport { useMachine, normalizeProps } from \"@zag-js/react\"\n\nexport function Tooltip() {\n  const service = useMachine(tooltip.machine, { id: \"1\" })\n\n  const api = tooltip.connect(service, normalizeProps)\n\n  return (\n    <>\n      <button {...api.getTriggerProps()}>Hover me</button>\n      {api.open && (\n        <div {...api.getPositionerProps()}>\n          <div {...api.getContentProps()}>Tooltip</div>\n        </div>\n      )}\n    </>\n  )\n}\n```\n\n### Customizing the timings\n\nBy default, the tooltip is designed to open after `1000ms` and close after\n`500ms`. You can customize this by passing the `openDelay` and `closeDelay`\ncontext properties.\n\n```jsx {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```jsx {2-4}\nconst service = useMachine(tooltip.machine, {\n  positioning: {\n    placement: \"bottom-start\",\n  },\n})\n```\n\nYou can configure other position-related properties in the `positioning` object.\nHere's what the positioning API looks like:\n\n```ts\nexport type PositioningOptions = {\n  /**\n   * The strategy to use for positioning\n   */\n  strategy?: \"absolute\" | \"fixed\"\n  /**\n   * The initial placement of the floating element\n   */\n  placement?: Placement\n  /**\n   * The offset of the floating element\n   */\n  offset?: { mainAxis?: number; crossAxis?: number }\n  /**\n   * The main axis offset or gap between the reference and floating elements\n   */\n  gutter?: number\n  /**\n   * Whether to flip the placement\n   */\n  flip?: boolean\n  /**\n   * Whether to make the floating element same width as the reference element\n   */\n  sameWidth?: boolean\n  /**\n   * The overflow boundary of the reference element\n   */\n  boundary?: Boundary\n  /**\n   * Options to activate auto-update listeners\n   */\n  listeners?: boolean | AutoUpdateOptions\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```jsx {6-8}\n//...\nconst api = popover.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### Pointerdown behavior\n\nBy default, the tooltip will close when the pointer is down on its trigger. To\nprevent this behavior, pass the `closeOnPointerDown` context property and set it\nto `false`.\n\n```jsx {2}\nconst service = useMachine(tooltip.machine, {\n  closeOnPointerDown: false,\n})\n```\n\n### Closing on Esc\n\nThe tooltip is designed to close when the escape key is pressed. To prevent\nthis, pass the `closeOnEscape` context property and set it to `false`.\n\n```jsx {2}\nconst service = useMachine(tooltip.machine, {\n  closeOnEsc: false,\n})\n```\n\n### Making the tooltip interactive\n\nSet the `interactive` context property to `true` to make them interactive.\n\nWhen a tooltip is interactive, it'll remain open even the pointer leaves the\ntrigger and move into the tooltip's content.\n\n```jsx {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```jsx {2-7}\nconst service = useMachine(tooltip.machine, {\n  onOpenChange(details) {\n    // details => { open: boolean }\n    console.log(details.open)\n  },\n})\n```\n\n## Styling guide\n\nEarlier, we mentioned that each tooltip part has a `data-part` attribute added\nto them to select and style them in the DOM.\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; 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**`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**`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-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-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"}