Skip to content
Kappa
Tooltip
@dicehub/kappav0.4.2

Tooltip

Shows a short, non-interactive label when an element receives keyboard focus or pointer hover.

<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

Typical part hierarchy
Tooltip.Root
├── Tooltip.Trigger
└── Tooltip.Content
    ├── Positioner + Teleport (automatic)
    ├── Tooltip.Arrow (default)
    │   └── Tooltip.ArrowTip
    └── short, non-interactive content

Kappa 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.

PropTypeDefaultDescription
openboolean-Controlled open state; supports v-model:open.
defaultOpenbooleanfalseInitial open state for uncontrolled use.
openDelaynumber400Delay before pointer hover opens the tooltip, in milliseconds. Keyboard focus opens without delay.
closeDelaynumber150Delay before the tooltip closes, in milliseconds.
disabledbooleanfalseDisables tooltip opening.
interactivebooleanfalseKeeps the tooltip open while the pointer is over its content. Prefer Popover for controls.
positioningTooltipPositioningOptionstop, 8 px gutterArk UI placement, collision, offset, and strategy options.
lazyMountbooleanfalseDefers content mounting until the first open state.
unmountOnExitbooleanfalseRemoves content after the close transition.
triggerValuestring | nullnullControlled active value for a root with multiple triggers.
idstringgeneratedStable identifier for the Ark UI machine.

Parts

PartElementDescription
Tooltip.TriggerbuttonHover and focus target. Use asChild to merge behavior into one control.
Tooltip.ContentdivPortalled tooltip surface with a default positioner and arrow.
Tooltip.ArrowdivPositioned arrow wrapper. Content renders it by default.
Tooltip.ArrowTipdivVisual arrow tip rendered by Arrow by default.
Tooltip.ContextslotExposes reactive Ark UI state to a scoped slot.
Tooltip.RootProviderslotAccepts a state machine created by useTooltip.

Tooltip.Content

PropTypeDefaultDescription
teleportbooleantrueMoves the positioner to teleportTo after mount.
teleportTostring | Element"body"Vue Teleport target for the popup.
showArrowbooleantrueShows the default Arrow and ArrowTip.
asChildbooleanfalseMerges content attributes into one child element.

Events

EventPayloadDescription
update:openbooleanEmitted when the controlled open state changes.
openChangeTooltipOpenChangeDetailsArk UI detail emitted after an open-state change.
update:triggerValuestring | nullEmitted when the active trigger changes.
triggerValueChangeTooltipTriggerValueChangeDetailsDetails for an active-trigger change.
exitCompletevoidEmitted after the close transition completes.

Exports

ExportDescription
TooltipCompound API exposing Root, RootProvider, Trigger, Content, Arrow, ArrowTip, and Context.
TooltipRootUnaugmented Ark UI state root.
TooltipRootProviderRoot backed by an external useTooltip state machine.
TooltipTriggerHover and focus target.
TooltipContentPortalled, positioned tooltip surface.
TooltipArrowArrow wrapper with a default ArrowTip.
TooltipArrowTipArrow tip primitive.
TooltipContextScoped-slot state access.
useTooltipCreates a Tooltip state machine for RootProvider.
useTooltipContextReads Tooltip state inside the compound component.
tooltipAnatomyArk UI part anatomy metadata.
TOOLTIP_DEFAULT_POSITIONINGKappa's viewport-aware top placement.