Tooltip

Displays informative text when users hover over or focus on an element

Usage

import { Tooltip } from '@hareui/vue'
<script setup lang="ts">import { Button, Tooltip } from '@hareui/vue'import { Icon } from '@iconify/vue'</script><template>  <div class="flex items-center gap-4">    <Tooltip :delay="0" text="This is a tooltip">      <Button variant="secondary">Hover me</Button>    </Tooltip>    <Tooltip :delay="0" text="More information">      <Button aria-label="More information" icon-only variant="tertiary">        <Icon icon="gravity-ui:circle-info" />      </Button>    </Tooltip>  </div></template>

Anatomy

Each Tooltip instance owns its own Reka TooltipProvider, so no app-level provider is needed. The first child is the trigger (as-child, merged directly onto its own root element — no extra wrapper is rendered); text or the #content slot supplies the floating content.

<Tooltip text="Helpful information about this element">
  <Button>Hover for tooltip</Button>
</Tooltip>

<!-- or, with the content slot and an arrow -->
<Tooltip arrow>
  <template #default><Button>Hover for tooltip</Button></template>
  <template #content>Helpful information about this element</template>
</Tooltip>

ui keys: base, arrow.

Examples

Placement

Hover buttons
<script setup lang="ts">import { Button, Tooltip } from '@hareui/vue'</script><template>  <div class="grid grid-cols-3 gap-4">    <div />    <Tooltip arrow :delay="0" side="top" text="Top placement">      <Button class="w-full" variant="tertiary">Top</Button>    </Tooltip>    <div />    <Tooltip arrow :delay="0" side="left" text="Left placement">      <Button class="w-full" variant="tertiary">Left</Button>    </Tooltip>    <div class="flex items-center justify-center">      <span class="text-sm text-muted">Hover buttons</span>    </div>    <Tooltip arrow :delay="0" side="right" text="Right placement">      <Button class="w-full" variant="tertiary">Right</Button>    </Tooltip>    <div />    <Tooltip arrow :delay="0" side="bottom" text="Bottom placement">      <Button class="w-full" variant="tertiary">Bottom</Button>    </Tooltip>    <div />  </div></template>

With Arrow

<script setup lang="ts">import { Button, Tooltip } from '@hareui/vue'</script><template>  <div class="flex items-center gap-4">    <Tooltip arrow :delay="0" text="Tooltip with arrow indicator">      <Button variant="secondary">With Arrow</Button>    </Tooltip>    <Tooltip arrow :delay="0" :side-offset="12" text="Custom offset from trigger">      <Button variant="primary">Custom Offset</Button>    </Tooltip>  </div></template>

Custom Triggers

The default slot's root element becomes the trigger. To use non-focusable content (an Avatar, a Chip, an icon), wrap it in an inline-block element with role="button" and tabindex="0" (the equivalent of HeroUI's Tooltip.Trigger) so the tooltip stays reachable from the keyboard.

JD
Active
<script setup lang="ts">import { Avatar, Chip, Tooltip } from '@hareui/vue'import { Icon } from '@iconify/vue'// Equivalent of HeroUI's `Tooltip.Trigger`: a focusable inline-block wrapper around non-button content.const triggerClass = 'inline-block outline-none focus-visible:status-focused'</script><template>  <div class="flex items-center gap-6">    <Tooltip arrow :delay="0">      <template #default>        <div aria-label="User avatar" :class="triggerClass" role="button" tabindex="0">          <Avatar alt="Jane Doe" fallback="JD" size="sm" src="https://img.heroui.chat/image/avatar?w=400&h=400&u=4" />        </div>      </template>      <template #content>        <div class="flex flex-col gap-0 py-1">          <p class="font-semibold">Jane Doe</p>          <p class="text-xs text-muted">[email protected]</p>        </div>      </template>    </Tooltip>    <Tooltip class="flex items-center gap-1.5" :delay="0">      <template #default>        <div aria-label="Status chip" :class="triggerClass" role="button" tabindex="0">          <Chip color="success">            <template #leading>              <!-- @gravity-ui/icons with only `width` keeps its default height="16" -->              <Icon height="16" icon="gravity-ui:circle-check-fill" width="12" />            </template>            <template #default>Active</template>          </Chip>        </div>      </template>      <template #content>        <span class="relative flex size-2">          <span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-success opacity-75" />          <span class="relative inline-flex size-2 rounded-full bg-success" />        </span>        <p>Jane is currently online</p>      </template>    </Tooltip>    <Tooltip arrow :delay="0">      <template #default>        <div aria-label="Info icon" :class="triggerClass" role="button" tabindex="0">          <div class="rounded-full bg-accent-soft p-2">            <Icon class="text-accent-soft-foreground" icon="gravity-ui:circle-question" />          </div>        </div>      </template>      <template #content>        <div class="max-w-xs px-1 py-1.5">          <p class="mb-1 font-semibold">Help Information</p>          <p class="text-sm text-muted">            This is a helpful tooltip with more detailed information about this feature.          </p>        </div>      </template>    </Tooltip>  </div></template>

Delays and Focus-Only Trigger

delay (default 1500) and close-delay (default 500) match HeroUI's --tooltip-delay / --tooltip-close-delay defaults. The close delay applies only when the pointer leaves the trigger or tooltip; moving back in cancels it. Blur, press, Escape and another tooltip opening close it immediately. trigger="focus" opens the tooltip only when the trigger gets focus, and hovering neither opens nor closes it.

<Tooltip :delay="0" :close-delay="1000" text="Stays open for a second">
  <Button variant="secondary">Close delay</Button>
</Tooltip>

<Tooltip trigger="focus" text="Shown on focus only">
  <Button variant="secondary">Focus me</Button>
</Tooltip>

Known differences from HeroUI

  • No cross-tooltip warm-up. React Aria shares one global timer, so once any tooltip has opened, the next one opens instantly. Each HareUI Tooltip has its own Reka provider, so every tooltip waits for its own delay.
  • Sub-pixel position drift. Reka positions the content with floating-ui and React Aria uses its own overlay maths. The two can differ by under a pixel.
  • Delays are props, not CSS variables. HeroUI reads its defaults from --tooltip-delay / --tooltip-close-delay at runtime. HareUI uses the same values as prop defaults, so changing those variables has no effect.

Customization

Tailwind CSS

<script setup lang="ts">import { Button, Tooltip } from '@hareui/vue'</script><template>  <Tooltip :delay="0" text="Copied to clipboard" :ui="{ base: 'rounded-lg border border-border/80 bg-surface px-2.5 py-1 text-xs text-foreground shadow-sm' }">    <Button variant="secondary">Share link</Button>  </Tooltip></template>

Global Configuration

To customize the Tooltip classes for the whole app, extend the tooltip theme in createHareUI:

app.use(createHareUI({
  ui: {
    tooltip: {
      slots: { base: 'rounded-xl shadow-lg' },
    },
  },
}))

Styling Reference

ui keydata-slotElement
base—The floating content (Reka TooltipContent)
arrowoverlay-arrowThe arrow SVG, rendered when arrow is true

Interactive States

  • data-[state=delayed-open] / data-[state=instant-open] — applied while the tooltip is open (entrance animation), mapped from HeroUI's [data-entering]
  • data-[state=closed] — applied while closing (exit animation), mapped from HeroUI's [data-exiting]
  • data-[side="top|right|bottom|left"] — the resolved placement, mapped from HeroUI's [data-placement]

API Reference

Props

PropTypeDefaultDescription
textstring-The text content of the tooltip. Ignored when the content slot is used.
openbooleanundefinedThe controlled open state of the tooltip. Use with v-model:open.
defaultOpenbooleanfalseThe open state of the tooltip when it is initially rendered. Use when you do not need to control its open state.
delaynumber1500Delay in milliseconds before the tooltip opens after the pointer enters the trigger.
closeDelaynumber500Delay in milliseconds before the tooltip closes after the pointer leaves the trigger (and the tooltip). Blur, press, Escape and opening another tooltip still close it immediately, as in React Aria.
trigger"focus" | "hover""hover"What opens the tooltip. 'hover' opens it on hover and on focus; 'focus' opens it only when the trigger receives focus (hovering neither opens nor closes it).
side"top" | "bottom" | "right" | "left""top"The preferred side of the trigger to render against.
align"center" | "start" | "end""center"The preferred alignment against the trigger.
sideOffsetnumber7 when `arrow` is true, otherwise 3The distance in pixels from the trigger.
arrowbooleanfalseWhether to render an arrow pointing at the trigger.
disabledbooleanfalseWhether the tooltip is disabled.
portalstring | boolean | HTMLElementtrueWhere the tooltip is teleported. true teleports to body, false renders in place, a string or element teleports to that target.
uiComponentSlots<{ slots: { base: string[]; arrow: string; }; }>-Per-slot class overrides.

Slots

SlotPropsDescription
default{ open: boolean; }The trigger element.
contentanyReplaces the default text content.

Emits

EventPayloadDescription
update:open[value: boolean]-

On this page

No Headings