Skip to content

EpTooltip

Props

NameDescriptionTypeDefault
delayDelay in milliseconds before showing the tooltip on hover.number0
positionPosition of the tooltip relative to the trigger element.string'top center'

Slots

NameDescription
tooltipTooltip content to display on hover
defaultTrigger element that shows the tooltip on hover

INFO

This component does not use events.

Component Code

vue
<template>
  <div
    class="ep-tooltip-wrapper"
    @mouseenter="showTooltip"
    @mouseleave="hideTooltip"
  >
    <div
      :class="['ep-tooltip', positionClass, { 'ep-tooltip--visible': visible }]"
    >
      <!-- @slot Tooltip content to display on hover -->
      <slot name="tooltip" />
    </div>
    <!-- @slot Trigger element that shows the tooltip on hover -->
    <slot />
  </div>
</template>

<script setup>
  import { computed, onBeforeUnmount, ref } from 'vue'

  defineOptions({
    name: 'EpTooltip',
  })

  const props = defineProps({
    /**
     * Delay in milliseconds before showing the tooltip on hover.
     */
    delay: {
      type: Number,
      default: 0,
    },
    /**
     * Position of the tooltip relative to the trigger element.
     * @values 'top left', 'top center', 'top right', 'right top', 'right center', 'right bottom', 'bottom left', 'bottom center', 'bottom right', 'left top', 'left center', 'left bottom'
     */
    position: {
      type: String,
      default: 'top center',
      validator: (value) =>
        [
          'top left',
          'top center',
          'top right',
          'right top',
          'right center',
          'right bottom',
          'bottom left',
          'bottom center',
          'bottom right',
          'left top',
          'left center',
          'left bottom',
        ].includes(value),
    },
  })

  const visible = ref(false)
  const timeoutId = ref(null)

  onBeforeUnmount(() => {
    clearTimeout(timeoutId.value)
  })

  const showTooltip = () => {
    timeoutId.value = setTimeout(() => {
      visible.value = true
    }, props.delay)
  }

  const hideTooltip = () => {
    clearTimeout(timeoutId.value)
    visible.value = false
  }

  const positionClass = computed(() => {
    return `ep-tooltip--${props.position.replace(' ', '-')}`
  })
</script>

Styles (SCSS)

scss
.ep-tooltip-wrapper {
  --ep-tooltip-bg-color: var(--interface-overlay);
  --ep-tooltip-text-color: var(--text-color);
  --ep-tooltip-offset: 0.5rem;
  position: relative;
  display: inline-block;
}

.ep-tooltip {
  position: absolute;
  background-color: var(--ep-tooltip-bg-color);
  color: var(--ep-tooltip-text-color);
  padding: 5px;
  border-radius: 4px;
  font-size: 12px;
  white-space: nowrap;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.3s ease;
  z-index: var(--z-index--tooltip);

  &.ep-tooltip--visible {
    visibility: visible;
    opacity: 1;
  }

  &.ep-tooltip--top-left {
    bottom: 100%;
    left: 0;
    transform: translateY(calc(-1 * var(--ep-tooltip-offset)));
  }

  &.ep-tooltip--top-center {
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%) translateY(calc(-1 * var(--ep-tooltip-offset)));
  }

  &.ep-tooltip--top-right {
    bottom: 100%;
    right: 0;
    transform: translateY(calc(-1 * var(--ep-tooltip-offset)));
  }

  &.ep-tooltip--right-top {
    top: 0;
    left: 100%;
    transform: translateX(var(--ep-tooltip-offset));
  }

  &.ep-tooltip--right-center {
    top: 50%;
    left: 100%;
    transform: translateX(var(--ep-tooltip-offset)) translateY(-50%);
  }

  &.ep-tooltip--right-bottom {
    bottom: 0;
    left: 100%;
    transform: translateX(var(--ep-tooltip-offset));
  }

  &.ep-tooltip--bottom-left {
    top: 100%;
    left: 0;
    transform: translateY(var(--ep-tooltip-offset));
  }

  &.ep-tooltip--bottom-center {
    top: 100%;
    left: 50%;
    transform: translateX(-50%) translateY(var(--ep-tooltip-offset));
  }

  &.ep-tooltip--bottom-right {
    top: 100%;
    right: 0;
    transform: translateY(var(--ep-tooltip-offset));
  }

  &.ep-tooltip--left-top {
    top: 0;
    right: 100%;
    transform: translateX(calc(-1 * var(--ep-tooltip-offset)));
  }

  &.ep-tooltip--left-center {
    top: 50%;
    right: 100%;
    transform: translateX(calc(-1 * var(--ep-tooltip-offset))) translateY(-50%);
  }

  &.ep-tooltip--left-bottom {
    bottom: 0;
    right: 100%;
    transform: translateX(calc(-1 * var(--ep-tooltip-offset)));
  }
}