Skip to content

Tooltip ​

It is commonly used to display prompt information when the mouse hover.

Basic Usage ​

Use placement to set position of Tooltip, and use content to set content of Tooltip.

vue
<template>
  <div class="max-w-600px mx-auto">
    <div class="flex justify-center">
      <re-tooltip placement="top-start" content="Top Start Text Prompt">
        <re-button>top-start</re-button>
      </re-tooltip>
      <re-tooltip placement="top" content="Top Center Text Prompt">
        <re-button>top</re-button>
      </re-tooltip>
      <re-tooltip placement="top-end" content="Top End Text Prompt">
        <re-button>top-end</re-button>
      </re-tooltip>
    </div>
    <div class="flex justify-between">
      <div class="flex flex-col items-start">
        <re-tooltip placement="left-start" width="120" content="Left Start Text Prompt">
          <re-button>left-start</re-button>
        </re-tooltip>
        <re-tooltip placement="left" width="120px" content="Left Middle Text Prompt">
          <re-button class="mt-1em ml-0!">left</re-button>
        </re-tooltip>
        <re-tooltip placement="left-end" width="120px" content="Left End Text Prompt">
          <re-button class="mt-1em ml-0!">left-end</re-button>
        </re-tooltip>
      </div>
      <div class="flex flex-col items-end">
        <re-tooltip placement="right-start" width="120px" content="Right Start Text Prompt">
          <re-button>right-start</re-button>
        </re-tooltip>
        <re-tooltip placement="right" width="120px" content="Right Center Text Prompt">
          <re-button class="mt-1em ml-0!">right</re-button>
        </re-tooltip>
        <re-tooltip placement="right-end" width="120px" content="Right End Text Prompt">
          <re-button class="mt-1em ml-0!">right-end</re-button>
        </re-tooltip>
      </div>
    </div>
    <div class="flex justify-center">
      <re-tooltip placement="bottom-start" content="Bottom Start Text Prompt">
        <re-button>bottom-start</re-button>
      </re-tooltip>
      <re-tooltip placement="bottom" content="Bottom Center Text Prompt">
        <re-button>bottom</re-button>
      </re-tooltip>
      <re-tooltip placement="bottom-end" content="Bottom End Text Prompt">
        <re-button>bottom-end</re-button>
      </re-tooltip>
    </div>
  </div>
</template>

Trigger ​

Use hover 、 click 、 focus and contextmenu to display Tooltip by trigger attribute.

vue
<template>
  <re-tooltip content="Tooltip text" trigger="hover">
    <re-button>Hover</re-button>
  </re-tooltip>
  <re-tooltip content="Tooltip text" trigger="click">
    <re-button>Click</re-button>
  </re-tooltip>
  <re-tooltip content="Tooltip text" trigger="focus">
    <re-button>Focus</re-button>
  </re-tooltip>
  <re-tooltip content="Tooltip text" trigger="contextmenu" placement="right">
    <re-button>Contextmenu</re-button>
  </re-tooltip>
</template>

Content ​

Use content or slot#content to set Tooltip content, is-html for render HTML content.

vue
<template>
  <re-tooltip content="<i>Text Content</i>" trigger="hover">
    <re-button>Text Content</re-button>
  </re-tooltip>
  <re-tooltip content="<i>HTML Content</i>" is-html trigger="hover">
    <re-button>HTML Content</re-button>
  </re-tooltip>
  <re-tooltip trigger="hover">
    <re-button>Slot Content</re-button>
    <template #content>
      <span style="color: var(--re-color-primary-base)">The Slot Content</span>
    </template>
  </re-tooltip>
</template>

Disabled ​

Use disabled to disable Tooltip.

vue
<template>
  <div>
    <re-tooltip :disabled="disabled" content="Disabled tooltip" trigger="hover">
      <re-button type="success" :disabled="disabled">
        {{ disabled ? 'Disabled' : 'Enabled' }}
      </re-button>
    </re-tooltip>

    <re-button class="ml-5em!" @click="toggle">Click to toggle</re-button>
  </div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'

const disabled = ref(false)

const toggle = () => {
  disabled.value = !disabled.value
}
</script>

Customize Boundary ​

Use boundary and rootBoundary to set Tooltip boundary.

vue
<template>
  <div>
    <div class="flex flex-wrap">
      <div
        ref="container1"
        class="h-300px grow basis-300px of-x-hidden of-y-auto text-center demo-border"
      >
        <div class="h-300px"></div>
        <re-tooltip
          v-if="container1"
          :boundary="container1"
          content="Scroll me to top boundary"
          :visible="visible"
        >
          <re-button>boundary: container</re-button>
        </re-tooltip>
        <div class="h-300px"></div>
      </div>
      <div
        ref="container2"
        class="h-300px grow flex basis-300px items-center of-x-auto demo-border"
      >
        <div class="w-500px shrink-0"></div>
        <re-tooltip
          v-if="container2"
          content="Scroll me to left boundary"
          :boundary="container2"
          :visible="visible"
          placement="left"
        >
          <re-button>boundary: container</re-button>
        </re-tooltip>
        <div class="w-500px shrink-0"></div>
      </div>
    </div>
    <div
      ref="container3"
      class="h-300px flex-1 of-hidden of-y-auto shrink-0 text-center demo-border"
    >
      <div class="h-300px"></div>
      <re-tooltip content="Scroll me to body top boundary" :visible="visible">
        <re-button>rootBoundary: 'viewport'</re-button>
      </re-tooltip>
      <div class="h-300px"></div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'

const visible = ref<boolean>(true)

const container1 = ref()
const container2 = ref()
const container3 = ref()

onMounted(() => {
  container1.value.scrollTo(0, 160)
  container2.value.scrollTo(220, 0)
  container3.value.scrollTo(0, 160)
})
</script>

Flip ​

By default, the Tooltip layer will auto flip based on the viewport, but when one of the below:
1、boundary: 'clippingAncestors' and altBoundary: true.
2、elementContext: 'reference'.
it will flip based on the parent container of the reference which is overflow: hidden/auto/scroll.
Otherwise, use flipOptions attribute for more behaviors.

vue
<template>
  <div class="flex flex-wrap">
    <div
      ref="container1"
      class="h-300px grow basis-300px of-hidden of-y-auto shrink-0 text-center demo-border"
    >
      <div class="h-300px"></div>
      <re-tooltip v-model:visible="visible" alt-boundary content="Scroll me to top boundary">
        <re-button>altBoundary: true</re-button>
      </re-tooltip>
      <div class="h-300px"></div>
    </div>
    <div
      ref="container2"
      class="h-300px grow basis-300px flex items-center min-w-0 of-x-auto demo-border"
    >
      <div class="w-500px shrink-0"></div>
      <re-tooltip
        content="Scroll me to left boundary"
        alt-boundary
        :visible="visible"
        placement="left"
      >
        <re-button>altBoundary: true</re-button>
      </re-tooltip>
      <div class="w-500px shrink-0"></div>
    </div>
  </div>
  <div class="flex flex-wrap">
    <div
      ref="container3"
      class="h-300px grow basis-300px of-hidden of-y-auto shrink-0 text-center demo-border"
    >
      <div class="h-300px"></div>
      <re-tooltip
        element-context="reference"
        content="elementContext: 'reference'"
        :visible="visible"
      >
        <re-button>Scroll me to top boundary</re-button>
      </re-tooltip>
      <div class="h-300px"></div>
    </div>
    <div
      ref="container4"
      class="h-300px grow basis-300px flex items-center min-w-0 of-x-auto demo-border"
    >
      <div class="w-500px shrink-0"></div>
      <re-tooltip
        content="elementContext: 'reference'"
        element-context="reference"
        :visible="visible"
        placement="left"
      >
        <re-button>Scroll me to left boundary</re-button>
      </re-tooltip>
      <div class="w-500px shrink-0"></div>
    </div>
  </div>
  <div class="flex flex-wrap">
    <div
      ref="container5"
      class="h-300px grow basis-300px of-hidden of-y-auto shrink-0 text-center demo-border"
    >
      <div class="h-300px"></div>
      <re-tooltip
        alt-boundary
        :flip-options="{ fallbackPlacements: ['top', 'right', 'bottom'] }"
        content="Scroll me to top boundary"
        :visible="visible"
      >
        <re-button class="mr-15em">altBoundary: true</re-button>
      </re-tooltip>
      <div class="h-300px"></div>
    </div>
    <div
      ref="container6"
      class="h-300px grow basis-300px flex items-center min-w-0 of-x-auto demo-border"
    >
      <div class="w-500px shrink-0"></div>
      <re-tooltip
        content="Scroll me to left boundary"
        alt-boundary
        :flip-options="{ fallbackPlacements: ['top', 'right', 'bottom'] }"
        :visible="visible"
        placement="left"
      >
        <re-button>altBoundary: true</re-button>
      </re-tooltip>
      <div class="w-500px shrink-0"></div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'

const visible = ref<boolean>(true)
const container1 = ref()
const container2 = ref()
const container3 = ref()
const container4 = ref()
const container5 = ref()
const container6 = ref()

onMounted(() => {
  container1.value.scrollTo(0, 160)
  container2.value.scrollTo(220, 0)
  container3.value.scrollTo(0, 160)
  container4.value.scrollTo(220, 0)
  container5.value.scrollTo(0, 160)
  container6.value.scrollTo(220, 0)
})
</script>

External Reference ​

Use is-external to activate external-ref, this allows you to place the reference element outside Tooltip.

Basic External Trigger Reference

Multiple External Trigger References for singleton

vue
<template>
  <p>Basic External Trigger Reference</p>
  <re-tooltip
    content="Tooltip text"
    trigger="hover"
    is-external
    :external-ref="externalRef"
  ></re-tooltip>
  <re-button ref="buttonRef" @mouseenter="setExternal">Hover me</re-button>

  <p>Multiple External Trigger References for singleton</p>
  <re-tooltip
    content="Tooltip text"
    trigger="hover"
    is-external
    :external-ref="hoverRef"
  ></re-tooltip>
  <re-button ref="buttonRef1" @mouseenter="setRef1()">Hover me 1</re-button>
  <re-button ref="buttonRef2" @mouseenter="setRef2()">Hover me 2</re-button>
  <re-button ref="buttonRef3" @mouseenter="setRef3()">Hover me 3</re-button>
  <p></p>
  <re-tooltip
    content="Tooltip text"
    trigger="click"
    is-external
    :external-ref="clickRef"
  ></re-tooltip>
  <re-button ref="buttonRef4" @click="setRef4()">Click me 1</re-button>
  <re-button ref="buttonRef5" @click="setRef5()">Click me 2</re-button>
  <re-button ref="buttonRef6" @click="setRef6()">Click me 3</re-button>
</template>
<script lang="ts" setup>
import { ref } from 'vue'

const buttonRef = ref()
const externalRef = ref()

const setExternal = () => {
  externalRef.value = buttonRef.value
}

const buttonRef1 = ref()
const buttonRef2 = ref()
const buttonRef3 = ref()

const hoverRef = ref()

const setRef1 = () => {
  hoverRef.value = buttonRef1.value
}
const setRef2 = () => {
  hoverRef.value = buttonRef2.value
}
const setRef3 = () => {
  hoverRef.value = buttonRef3.value
}

const buttonRef4 = ref()
const buttonRef5 = ref()
const buttonRef6 = ref()

const clickRef = ref()

const setRef4 = () => {
  clickRef.value = buttonRef4.value
}
const setRef5 = () => {
  clickRef.value = buttonRef5.value
}
const setRef6 = () => {
  clickRef.value = buttonRef6.value
}
</script>

Virtual Reference ​

Use is-virtual to activate virtual-ref, it accepts an object with layout properties to build the reference, visible maybe is needed.

vue
<template>
  <re-tooltip
    content="Tooltip text"
    :visible="visible"
    is-virtual
    :virtual-ref="virtualRef"
  ></re-tooltip>
  <re-button @click="visible = !visible">Click me</re-button>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from 'vue'

const visible = ref<boolean>(false)

const position = ref<Record<string, number>>({
  width: 0,
  height: 0,
  x: 0,
  y: 0,
  top: 0,
  left: 0,
  right: 0,
  bottom: 0
})

const virtualRef = ref({
  getBoundingClientRect: () => position.value
})

const move = ({ clientX, clientY }: MouseEvent) => {
  position.value = {
    width: 0,
    height: 0,
    x: clientX,
    y: clientY,
    top: clientY,
    left: clientX,
    right: clientX,
    bottom: clientY
  }
}

onMounted(() => {
  document.addEventListener('mousemove', move)
})
onUnmounted(() => {
  document.removeEventListener('mousemove', move)
})
</script>

Selection Range Build A Virtual Reference ​

Use is-virtual to activate virtual-ref, it also allows a selection Range to build the reference.

Select the text to visible the Tooltip
vue
<template>
  <re-tooltip
    content="Tooltip text"
    :visible="visible"
    is-virtual
    :virtual-ref="rangeRef"
  ></re-tooltip>
  <span ref="textRef">Select the text to visible the Tooltip</span>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
const visible = ref<boolean>(false)

const textRef = ref<HTMLSpanElement | null>(null)
const range = ref<Range | null>()

const rangeRef = {
  getBoundingClientRect: () => range.value?.getBoundingClientRect(),
  getClientRects: () => range.value?.getClientRects()
}

const mouseup = (e: MouseEvent | TouchEvent) => {
  range.value?.selectNode(textRef.value!)
  const selection = window.getSelection()

  if (!textRef.value || !selection || selection.rangeCount === 0) return

  const currentRange = selection.getRangeAt(0)
  const container = currentRange.commonAncestorContainer
  const text = selection.toString().trim()

  // Ensure the selection originates from the target element
  if (textRef.value.contains(container!)) {
    range.value = currentRange.cloneRange()
    visible.value = !!text
  }
}

const selectionChange = () => {
  const selection = window.getSelection()
  const text = selection?.toString()?.trim()

  if (!text) {
    visible.value = false
  }
}

onMounted(() => {
  document.addEventListener('mouseup', mouseup)
  document.addEventListener('touchend', mouseup)
  document.addEventListener('selectionchange', selectionChange)
})

onBeforeUnmount(() => {
  document.removeEventListener('mouseup', mouseup)
  document.removeEventListener('touchend', mouseup)
  document.removeEventListener('selectionchange', selectionChange)
})
</script>

Tooltip Attributes ​

NameDescriptionTypeDefault
placementTooltip positionenumtop
triggerThe trigger event nameenumhover
contentTooltip contentstring—
is-htmlWhether content is treated as HTML stringboolean—
disabledWhether Tooltip is disabledboolean—
visible / v-model:visibleWhether Tooltip is visibleboolean—
offsetOffset from the reference edge. See Floating UI OffsetOptions for detailsnumber | interface10
widthTooltip widthnumber | string—
heightTooltip heightnumber | string—
max-widthTooltip max widthnumber | string—
max-heightTooltip max heightnumber | string—
themeTooltip theme'dark' |'light'dark
reverse-themewhether to reverse Tooltip theme colorbooleanfalse
append-toTarget element for appending TooltipcssSelector | HTMLElementbody
teleportedWhether to teleport Tooltip to the appendTo targetbooleantrue
persistentWhether to keep the floating open on hoverbooleantrue
click-to-toggleWhether to toggle the floating on click, only trigger='click' booleantrue
floating-classCustom class for the floatingstring | object | Array —
floating-styleCustom style for the floatingstring | object | Array—
show-delayDelay(ms) before Tooltip appears , but not effective when visible is present or is-virtual or is-externalnumber0
hide-delayDelay(ms) before Tooltip disappears , but not effective when visible is present or is-virtual or is-externalnumber200
show-arrowWhether to show arrow for Tooltipbooleantrue
arrow-sizeThe arrow sizenumber8
arrow-offsetPadding between the arrow and the Tooltip edgenumber4
arrow-optionsFloating UI ArrowOptions Parametersinterface—
transitionName of Vue3 Transition componentstringtooltip
css-transitionCss of Vue3 Transition componentbooleantrue
transformWhether to use transform positioning instead of top/left positioningbooleantrue
strategyThe type of CSS position property to use'absolute' | 'fixed'absolute
css-durationDuration of Vue3 Transition component for fade in/fade outnumber300
boundaryBoundary of Floating UI DetectOverflowOptions : interfaceunionclippingAncestors
alt-boundaryAltBoundary of Floating UI DetectOverflowOptionsbooleanfalse
root-boundaryRootBoundary of Floating UI DetectOverflowOptionsunionviewport
element-contextElementContext of Floating UI DetectOverflowOptions'reference' | 'floating'floating
flip-offsetOffset from boundary before flipping, Padding of Floating UI DetectOverflowOptionsunion8
flip-optionsFloating UI FlipOptions Parametersinterface—
inline-optionsFloating UI InlineOptions Parametersinterface—
is-externalWhether external reference is enabledboolean—
external-refExternal reference targetHTMLElement—
is-virtualWhether virtual reference is enabledboolean—
virtual-refVirtual reference object for Floating UI VirtualElementinterface—

Tooltip Events ​

NameDescriptionParameters
before-enterVue3 <Transition> event hookFunction
enterVue3 <Transition> event hookFunction
after-enterVue3 <Transition> event hookFunction
before-leaveVue3 <Transition> event hookFunction
leaveVue3 <Transition> event hookFunction
after-leaveVue3 <Transition> event hookFunction
enter-cancelledVue3 <Transition> event hookFunction
leave-cancelledVue3 <Transition> event hookFunction

Tooltip Slots ​

NameDescription
defaultCustomize default reference
contentCustomize default content

Tooltip Exposes ​

NameDescriptionType
updateManually updates the Tooltip positionFunction
showManually show the TooltipFunction
hideManually hide the TooltipFunction
triggerRefThe trigger refernce elementHTMLElement
floatingRefThe Tooltip layer elementHTMLElement
arrowRefThe Tooltip arrow elementHTMLElement

基于 MIT 许可证发布。