<script setup>
import { Plus } from "@lucide/vue";
import { Button } from "@dicehub/kappa/components/button";
import { Tooltip } from "@dicehub/kappa/components/tooltip";
</script>
<template>
<Tooltip.Root>
<Tooltip.Trigger as-child>
<Button :icon="Plus" shape="square" variant="outline" aria-label="Add item" />
</Tooltip.Trigger>
<Tooltip.Content>Add item</Tooltip.Content>
</Tooltip.Root>
</template>Installation
Tooltip is part of the main Kappa package. Ark UI supplies hover, focus, Escape, described-by relationships, collision handling, and shared delay behavior.
Barrel
import {
Tooltip,
TooltipRoot,
TooltipTrigger,
TooltipContent,
} from "@dicehub/kappa";Granular
import {
Tooltip,
TooltipRoot,
TooltipTrigger,
TooltipContent,
} from "@dicehub/kappa/components/tooltip";Usage
Use asChild on Trigger to keep the original Button, Link, or control as the only interactive element. Keep content short and non-interactive.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
import { Tooltip } from "@dicehub/kappa/components/tooltip";
</script>
<template>
<Tooltip.Root>
<Tooltip.Trigger as-child>
<Button variant="outline">Hover or focus</Button>
</Tooltip.Trigger>
<Tooltip.Content>Review component details</Tooltip.Content>
</Tooltip.Root>
</template>Composition
Tooltip.Root
├── Tooltip.Trigger
└── Tooltip.Content
├── Positioner + Teleport (automatic)
├── Tooltip.Arrow (default)
│ └── Tooltip.ArrowTip
└── short, non-interactive contentKappa follows Ark UI state and part contracts. Tooltip.Content adds the positioner, safe Vue Teleport, and default Arrow so the common composition stays small. Use the named parts or the arrow slot when a custom surface needs them.
Kappa intentionally defaults to a top placement with an 8 px gutter. Pass Ark UIpositioning options to change placement, offsets, collision behavior, or the fixed-position strategy.
<Tooltip.Root>
<Tooltip.Trigger as-child>
<Button>Trigger</Button>
</Tooltip.Trigger>
<Tooltip.Content>
Tooltip text
<template #arrow>
<Tooltip.Arrow><Tooltip.ArrowTip /></Tooltip.Arrow>
</template>
</Tooltip.Content>
</Tooltip.Root>Examples
Sides
Set positioning.placement to place the tooltip on any side of its trigger.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
import { Tooltip } from "@dicehub/kappa/components/tooltip";
const sides = ["left", "top", "bottom", "right"];
</script>
<template>
<Tooltip.Root
v-for="side in sides"
:key="side"
:positioning="{ placement: side }"
>
<Tooltip.Trigger as-child>
<Button size="sm" variant="outline">{{ side }}</Button>
</Tooltip.Trigger>
<Tooltip.Content>{{ side }} tooltip</Tooltip.Content>
</Tooltip.Root>
</template>With Keyboard Shortcut
Pair a short label with a compact shortcut hint.
<script setup>
import { Save } from "@lucide/vue";
import { Button } from "@dicehub/kappa/components/button";
import { Tooltip } from "@dicehub/kappa/components/tooltip";
</script>
<template>
<Tooltip.Root>
<Tooltip.Trigger as-child>
<Button :icon="Save" variant="outline">Save changes</Button>
</Tooltip.Trigger>
<Tooltip.Content>
<span>Save changes</span>
<kbd>Ctrl S</kbd>
</Tooltip.Content>
</Tooltip.Root>
</template>Disabled Button
Wrap a disabled control in a focusable trigger because disabled elements do not receive focus or pointer events reliably.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
import { Tooltip } from "@dicehub/kappa/components/tooltip";
</script>
<template>
<Tooltip.Root>
<Tooltip.Trigger as-child>
<span class="disabled-trigger" tabindex="0">
<Button disabled>Deploy update</Button>
</span>
</Tooltip.Trigger>
<Tooltip.Content>Available after validation passes</Tooltip.Content>
</Tooltip.Root>
</template>
<style scoped>
.disabled-trigger { display: inline-flex; }
.disabled-trigger .kappa-button { pointer-events: none; }
</style>Delay Control
Tune open and close timing for immediate guidance or dense groups of controls.
<Tooltip.Root :open-delay="0">
<Tooltip.Trigger as-child><Button>Instant</Button></Tooltip.Trigger>
<Tooltip.Content>Opens without delay</Tooltip.Content>
</Tooltip.Root>
<Tooltip.Root>
<Tooltip.Trigger as-child><Button>Default</Button></Tooltip.Trigger>
<Tooltip.Content>Opens after 400 ms</Tooltip.Content>
</Tooltip.Root>
<Tooltip.Root :open-delay="900" :close-delay="300">
<Tooltip.Trigger as-child><Button>Custom delay</Button></Tooltip.Trigger>
<Tooltip.Content>Custom open and close timing</Tooltip.Content>
</Tooltip.Root>Long Content and Overflow
Content wraps against the available viewport width instead of crossing the page edge.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
import { Tooltip } from "@dicehub/kappa/components/tooltip";
const content =
"This explanation stays inside the viewport and wraps when space becomes narrow.";
</script>
<template>
<div class="edge-row">
<Tooltip.Root
v-for="label in ['Near left edge', 'Centered', 'Near right edge']"
:key="label"
:positioning="{ placement: 'bottom' }"
>
<Tooltip.Trigger as-child><Button>{{ label }}</Button></Tooltip.Trigger>
<Tooltip.Content>{{ content }}</Tooltip.Content>
</Tooltip.Root>
</div>
</template>Controlled
Use v-model:open when application state must observe or control the tooltip.
<script setup>
import { ref } from "vue";
import { Button } from "@dicehub/kappa/components/button";
import { Tooltip } from "@dicehub/kappa/components/tooltip";
const open = ref(false);
</script>
<template>
<Tooltip.Root v-model:open="open" :open-delay="0">
<Tooltip.Trigger as-child><Button>Focus state</Button></Tooltip.Trigger>
<Tooltip.Content>The open state is synchronized with Vue.</Tooltip.Content>
</Tooltip.Root>
<output>Tooltip: {{ open ? "open" : "closed" }}</output>
</template>Accessibility
- Pointer hover and keyboard focus open the same tooltip.
- Keyboard focus opens without the pointer delay. Escape closes the open tooltip.
- Ark UI links Trigger and Content through
aria-describedby. - Tooltip content must not contain controls, links, or information required to finish a task.
- Use a visible label when space permits. A tooltip does not replace an accessible name.
- Wrap a disabled control in a focusable element because native disabled controls cannot receive focus.
- Opening motion honors
prefers-reduced-motion; forced colors keep a visible boundary.
Use Popover when the floating content must accept input or contain actions.
API Reference
Tooltip.Root
Owns Ark UI open state, delay, active trigger, and positioning.
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | - | Controlled open state; supports v-model:open. |
defaultOpen | boolean | false | Initial open state for uncontrolled use. |
openDelay | number | 400 | Delay before pointer hover opens the tooltip, in milliseconds. Keyboard focus opens without delay. |
closeDelay | number | 150 | Delay before the tooltip closes, in milliseconds. |
disabled | boolean | false | Disables tooltip opening. |
interactive | boolean | false | Keeps the tooltip open while the pointer is over its content. Prefer Popover for controls. |
positioning | TooltipPositioningOptions | top, 8 px gutter | Ark UI placement, collision, offset, and strategy options. |
lazyMount | boolean | false | Defers content mounting until the first open state. |
unmountOnExit | boolean | false | Removes content after the close transition. |
triggerValue | string | null | null | Controlled active value for a root with multiple triggers. |
id | string | generated | Stable identifier for the Ark UI machine. |
Parts
| Part | Element | Description |
|---|---|---|
Tooltip.Trigger | button | Hover and focus target. Use asChild to merge behavior into one control. |
Tooltip.Content | div | Portalled tooltip surface with a default positioner and arrow. |
Tooltip.Arrow | div | Positioned arrow wrapper. Content renders it by default. |
Tooltip.ArrowTip | div | Visual arrow tip rendered by Arrow by default. |
Tooltip.Context | slot | Exposes reactive Ark UI state to a scoped slot. |
Tooltip.RootProvider | slot | Accepts a state machine created by useTooltip. |
Tooltip.Content
| Prop | Type | Default | Description |
|---|---|---|---|
teleport | boolean | true | Moves the positioner to teleportTo after mount. |
teleportTo | string | Element | "body" | Vue Teleport target for the popup. |
showArrow | boolean | true | Shows the default Arrow and ArrowTip. |
asChild | boolean | false | Merges content attributes into one child element. |
Events
| Event | Payload | Description |
|---|---|---|
update:open | boolean | Emitted when the controlled open state changes. |
openChange | TooltipOpenChangeDetails | Ark UI detail emitted after an open-state change. |
update:triggerValue | string | null | Emitted when the active trigger changes. |
triggerValueChange | TooltipTriggerValueChangeDetails | Details for an active-trigger change. |
exitComplete | void | Emitted after the close transition completes. |
Exports
| Export | Description |
|---|---|
Tooltip | Compound API exposing Root, RootProvider, Trigger, Content, Arrow, ArrowTip, and Context. |
TooltipRoot | Unaugmented Ark UI state root. |
TooltipRootProvider | Root backed by an external useTooltip state machine. |
TooltipTrigger | Hover and focus target. |
TooltipContent | Portalled, positioned tooltip surface. |
TooltipArrow | Arrow wrapper with a default ArrowTip. |
TooltipArrowTip | Arrow tip primitive. |
TooltipContext | Scoped-slot state access. |
useTooltip | Creates a Tooltip state machine for RootProvider. |
useTooltipContext | Reads Tooltip state inside the compound component. |
tooltipAnatomy | Ark UI part anatomy metadata. |
TOOLTIP_DEFAULT_POSITIONING | Kappa's viewport-aware top placement. |