# Tooltip

URL: https://ark-ui.com/docs/components/tooltip
LLM: https://ark-ui.com/llms.txt/components/tooltip

A label that provides information on hover or focus.

---



## Anatomy



```tsx
<Tooltip.Root>
  <Tooltip.Trigger />
  <Tooltip.Positioner>
    <Tooltip.Arrow>
      <Tooltip.ArrowTip />
    </Tooltip.Arrow>
    <Tooltip.Content />
  </Tooltip.Positioner>
</Tooltip.Root>
```

## Examples

```tsx
import { Tooltip } from '@ark-ui/react/tooltip'
import { Portal } from '@ark-ui/react/portal'
import styles from 'styles/tooltip.module.css'

export const Basic = () => (
  <Tooltip.Root>
    <Tooltip.Trigger className={styles.Trigger}>Hover Me</Tooltip.Trigger>
    <Portal>
      <Tooltip.Positioner>
        <Tooltip.Content className={styles.Content}>I am a tooltip!</Tooltip.Content>
      </Tooltip.Positioner>
    </Portal>
  </Tooltip.Root>
)
```

### Controlled

To create a controlled Tooltip component, manage the state of whether the tooltip is open using the `open` prop:

```tsx
import { Portal } from '@ark-ui/react/portal'
import { Tooltip } from '@ark-ui/react/tooltip'
import { useState } from 'react'
import styles from 'styles/tooltip.module.css'
import button from 'styles/button.module.css'

export const Controlled = () => {
  const [open, setOpen] = useState(false)
  return (
    <div className="stack">
      <button type="button" onClick={() => setOpen(!open)} className={button.Root}>
        Toggle
      </button>
      <Tooltip.Root open={open} onOpenChange={(e) => setOpen(e.open)}>
        <Tooltip.Trigger className={styles.Trigger}>Hover Me</Tooltip.Trigger>
        <Portal>
          <Tooltip.Positioner>
            <Tooltip.Content className={styles.Content}>I am a tooltip!</Tooltip.Content>
          </Tooltip.Positioner>
        </Portal>
      </Tooltip.Root>
    </div>
  )
}
```

### Root Provider

An alternative way to control the tooltip is to use the `RootProvider` component and the `useTooltip` hook. This way you
can access the state and methods from outside the component.

```tsx
import { Tooltip, useTooltip } from '@ark-ui/react/tooltip'
import { Portal } from '@ark-ui/react/portal'
import styles from 'styles/tooltip.module.css'

export const RootProvider = () => {
  const tooltip = useTooltip()

  return (
    <>
      <output>Open: {String(tooltip.open)}</output>
      <Tooltip.RootProvider value={tooltip}>
        <Tooltip.Trigger className={styles.Trigger}>Hover Me</Tooltip.Trigger>
        <Portal>
          <Tooltip.Positioner>
            <Tooltip.Content className={styles.Content}>I am a tooltip!</Tooltip.Content>
          </Tooltip.Positioner>
        </Portal>
      </Tooltip.RootProvider>
    </>
  )
}
```

### Arrow

To display an arrow pointing to the trigger from the tooltip, use the `Tooltip.Arrow` and `Tooltip.ArrowTip` components:

```tsx
import { Tooltip } from '@ark-ui/react/tooltip'
import { Portal } from '@zag-js/react'
import styles from 'styles/tooltip.module.css'

export const Arrow = () => (
  <Tooltip.Root>
    <Tooltip.Trigger className={styles.Trigger}>Hover Me</Tooltip.Trigger>
    <Portal>
      <Tooltip.Positioner>
        <Tooltip.Content className={styles.Content}>
          <Tooltip.Arrow className={styles.Arrow}>
            <Tooltip.ArrowTip className={styles.ArrowTip} />
          </Tooltip.Arrow>
          I am a tooltip!
        </Tooltip.Content>
      </Tooltip.Positioner>
    </Portal>
  </Tooltip.Root>
)
```

### Delay

To configure the open and close delay for the Tooltip, use the `closeDelay` and `openDelay` props:

```tsx
import { Tooltip } from '@ark-ui/react/tooltip'
import { Portal } from '@ark-ui/react/portal'
import styles from 'styles/tooltip.module.css'

export const Delay = () => (
  <Tooltip.Root closeDelay={0} openDelay={0}>
    <Tooltip.Trigger className={styles.Trigger}>Hover Me</Tooltip.Trigger>
    <Portal>
      <Tooltip.Positioner>
        <Tooltip.Content className={styles.Content}>I am a tooltip!</Tooltip.Content>
      </Tooltip.Positioner>
    </Portal>
  </Tooltip.Root>
)
```

### Positioning

To customize the position of the Tooltip relative to the trigger, use the `positioning` prop:

```tsx
import { Tooltip } from '@ark-ui/react/tooltip'
import { Portal } from '@ark-ui/react/portal'
import styles from 'styles/tooltip.module.css'

export const Positioning = () => (
  <Tooltip.Root
    positioning={{
      placement: 'left-start',
      offset: { mainAxis: 12, crossAxis: 12 },
    }}
  >
    <Tooltip.Trigger className={styles.Trigger}>Hover Me</Tooltip.Trigger>
    <Portal>
      <Tooltip.Positioner>
        <Tooltip.Content className={styles.Content}>I am a tooltip!</Tooltip.Content>
      </Tooltip.Positioner>
    </Portal>
  </Tooltip.Root>
)
```

### Context

Access the tooltip's state and methods with `Tooltip.Context` or the `useTooltipContext` hook:

```tsx
import { Portal } from '@ark-ui/react/portal'
import { Tooltip } from '@ark-ui/react/tooltip'
import styles from 'styles/tooltip.module.css'

export const Context = () => (
  <Tooltip.Root>
    <Tooltip.Trigger className={styles.Trigger}>Hover Me</Tooltip.Trigger>
    <Portal>
      <Tooltip.Positioner>
        <Tooltip.Context>
          {(tooltip) => (
            <Tooltip.Content className={styles.Content}>
              This tooltip is open: {tooltip.open.toString()}
            </Tooltip.Content>
          )}
        </Tooltip.Context>
      </Tooltip.Positioner>
    </Portal>
  </Tooltip.Root>
)
```

### Within Fixed Containers

When rendering a tooltip inside a fixed-position container, set `positioning.strategy` to `"fixed"` to ensure proper
positioning.

```tsx
import { Portal } from '@ark-ui/react/portal'
import { Tooltip } from '@ark-ui/react/tooltip'
import styles from 'styles/tooltip.module.css'

export const WithinFixed = () => (
  <div style={{ position: 'fixed', top: '40px', left: '40px', padding: '40px', background: 'red' }}>
    <Tooltip.Root positioning={{ strategy: 'fixed' }}>
      <Tooltip.Trigger className={styles.Trigger}>Hover Me</Tooltip.Trigger>
      <Portal>
        <Tooltip.Positioner>
          <Tooltip.Content className={styles.Content}>I am a tooltip!</Tooltip.Content>
        </Tooltip.Positioner>
      </Portal>
    </Tooltip.Root>
  </div>
)
```

### Multiple Triggers

Share a single tooltip across multiple trigger elements. Pass a `value` to each `Tooltip.Trigger` — the tooltip
repositions to whichever trigger is hovered without closing.

```tsx
import { Portal } from '@ark-ui/react/portal'
import { Tooltip } from '@ark-ui/react/tooltip'
import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon } from 'lucide-react'
import { useState } from 'react'
import styles from 'styles/tooltip.module.css'

interface Tool {
  id: string
  label: string
  shortcut: string
  icon: React.ElementType
}

const tools: Tool[] = [
  { id: 'bold', label: 'Bold', shortcut: '⌘+B', icon: BoldIcon },
  { id: 'italic', label: 'Italic', shortcut: '⌘+I', icon: ItalicIcon },
  { id: 'underline', label: 'Underline', shortcut: '⌘+U', icon: UnderlineIcon },
  { id: 'strikethrough', label: 'Strikethrough', shortcut: '⌘+⇧+X', icon: StrikethroughIcon },
]

export const MultipleTriggers = () => {
  const [activeTool, setActiveTool] = useState<Tool | null>(null)

  return (
    <Tooltip.Root
      onTriggerValueChange={(e) => {
        setActiveTool(tools.find((t) => t.id === e.value) ?? null)
      }}
    >
      <div className={styles.Toolbar}>
        {tools.map((tool) => (
          <Tooltip.Trigger key={tool.id} value={tool.id} className={styles.ToolbarButton}>
            <tool.icon />
          </Tooltip.Trigger>
        ))}
      </div>
      <Portal>
        <Tooltip.Positioner>
          <Tooltip.Content className={styles.Content}>
            {activeTool && (
              <>
                {activeTool.label} <span className={styles.Shortcut}>{activeTool.shortcut}</span>
              </>
            )}
          </Tooltip.Content>
        </Tooltip.Positioner>
      </Portal>
    </Tooltip.Root>
  )
}
```

## API Reference

### Props

### Root

#### Props

**`aria-label`**
Type: `string`
Required: false
Default Value: `undefined`
Description: Custom label for the tooltip.

**`closeDelay`**
Type: `number`
Required: false
Default Value: `150`
Description: The close delay of the tooltip.

**`closeOnClick`**
Type: `boolean`
Required: false
Default Value: `true`
Description: Whether the tooltip should close on click

**`closeOnEscape`**
Type: `boolean`
Required: false
Default Value: `true`
Description: Whether to close the tooltip when the Escape key is pressed.

**`closeOnPointerDown`**
Type: `boolean`
Required: false
Default Value: `true`
Description: Whether to close the tooltip on pointerdown.

**`closeOnScroll`**
Type: `boolean`
Required: false
Default Value: `true`
Description: Whether the tooltip should close on scroll

**`defaultOpen`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: The initial open state of the tooltip when rendered.
Use when you don't need to control the open state of the tooltip.

**`defaultTriggerValue`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The initial trigger value when rendered.
Use when you don't need to control the trigger value.

**`disabled`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Whether the tooltip is disabled

**`hideMode`**
Type: `HideMode`
Required: false
Default Value: `'display-none'`
Description: How to hide content when mounted but not present.
- `'display-none'`: HTML `hidden` attribute. Effects stay alive.
- `'activity'`: React 19 `<Activity mode="hidden">`. Effects pause. Requires React 19+.

**`id`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The unique identifier of the machine.

**`ids`**
Type: `Partial<{
  trigger: string | ((value?: string | undefined) => string)
  content: string
  arrow: string
  positioner: string
}>`
Required: false
Default Value: `undefined`
Description: The ids of the elements in the tooltip. Useful for composition.

**`immediate`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Whether to synchronize the present change immediately or defer it to the next frame

**`interactive`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether the tooltip's content is interactive.
In this mode, the tooltip will remain open when user hovers over the content.

**`lazyMount`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to enable lazy mounting

**`onExitComplete`**
Type: `VoidFunction`
Required: false
Default Value: `undefined`
Description: Function called when the animation ends in the closed state

**`onOpenChange`**
Type: `(details: OpenChangeDetails) => void`
Required: false
Default Value: `undefined`
Description: Function called when the tooltip is opened.

**`onTriggerValueChange`**
Type: `(details: TriggerValueChangeDetails) => void`
Required: false
Default Value: `undefined`
Description: Function called when the trigger value changes.

**`open`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: The controlled open state of the tooltip

**`openDelay`**
Type: `number`
Required: false
Default Value: `400`
Description: The open delay of the tooltip.

**`positioning`**
Type: `PositioningOptions`
Required: false
Default Value: `undefined`
Description: The user provided options used to position the popover content

**`present`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Whether the node is present (controlled by the user)

**`skipAnimationOnMount`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to allow the initial presence animation.

**`triggerValue`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The controlled trigger value

**`unmountOnExit`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to unmount on exit.

### Arrow

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

### ArrowTip

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

### Content

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

#### Data Attributes

**`data-scope`**: tooltip
**`data-part`**: content
**`data-state`**: "open" | "closed"
**`data-instant`**: 
**`data-placement`**: The placement of the content
**`data-side`**: The side of the trigger that the content is positioned on

### Positioner

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

### RootProvider

#### Props

**`value`**
Type: `UseTooltipReturn`
Required: true
Default Value: `undefined`
Description: undefined

**`hideMode`**
Type: `HideMode`
Required: false
Default Value: `'display-none'`
Description: How to hide content when mounted but not present.
- `'display-none'`: HTML `hidden` attribute. Effects stay alive.
- `'activity'`: React 19 `<Activity mode="hidden">`. Effects pause. Requires React 19+.

**`immediate`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Whether to synchronize the present change immediately or defer it to the next frame

**`lazyMount`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to enable lazy mounting

**`onExitComplete`**
Type: `VoidFunction`
Required: false
Default Value: `undefined`
Description: Function called when the animation ends in the closed state

**`present`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Whether the node is present (controlled by the user)

**`skipAnimationOnMount`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to allow the initial presence animation.

**`unmountOnExit`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to unmount on exit.

### Trigger

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

**`value`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The value that identifies this specific trigger

#### Data Attributes

**`data-scope`**: tooltip
**`data-part`**: trigger
**`data-value`**: The value of the item
**`data-current`**: Present when current
**`data-expanded`**: Present when expanded
**`data-state`**: "open" | "closed"

### Context

**API:**

| Property | Type | Description |
|----------|------|-------------|
| `open` | `boolean` | Whether the tooltip is open. |
| `setOpen` | `(open: boolean) => void` | Function to open the tooltip. |
| `triggerValue` | `string | null` | The trigger value |
| `setTriggerValue` | `(value: string | null) => void` | Function to set the trigger value |
| `reposition` | `(options?: Partial<PositioningOptions>) => void` | Function to reposition the popover |


## Accessibility

Complies with the [Tooltip WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/).

### Keyboard Support

**`Tab`**
Description: Opens/closes the tooltip without delay.

**`Escape`**
Description: If open, closes the tooltip without delay.