Skip to content

Popconfirm ​

A floating card triggered by hover、click、focus or contextmenu. Built on top of Tooltip.

Basic Usage ​

Use placement to set position of Popconfirm, and use content to set content of Popconfirm. Click to trigger below Popconfirm.

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

Title ​

Use title or slot#title to provide the title.

vue
<template>
  <re-popconfirm title="Are you sure to delete it?" max-width="200">
    <re-button>Delete</re-button>
  </re-popconfirm>
  <re-popconfirm max-width="200">
    <template #title>
      <div style="color: var(--re-color-primary-base); font-size: 16px">Is it a Slot Title?</div>
    </template>
    <re-button>Slot Title</re-button>
  </re-popconfirm>
</template>

Trigger ​

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

vue
<template>
  <re-popconfirm width="200" title="Something need your confirm" trigger="hover">
    <re-button>Hover</re-button>
  </re-popconfirm>
  <re-popconfirm width="200" title="Are you sure?" trigger="click">
    <re-button>Click</re-button>
  </re-popconfirm>
  <re-popconfirm width="200" title="How do you do?" trigger="focus">
    <re-button>Focus</re-button>
  </re-popconfirm>
  <re-popconfirm width="200" title="Is it easy to use?" trigger="contextmenu" placement="right">
    <re-button>Contextmenu</re-button>
  </re-popconfirm>
</template>

Content ​

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

vue
<template>
  <re-popconfirm content="<i>Well?</i>" title="Is it easy to use?">
    <re-button>Text Content</re-button>
  </re-popconfirm>
  <re-popconfirm content="<i>Well?</i>" is-html title="Is it easy to use?">
    <re-button>HTML Content</re-button>
  </re-popconfirm>
  <re-popconfirm title="Is it easy to use?" max-width="280">
    <re-button>Slot Content</re-button>
    <template #content>
      <div style="color: var(--re-color-warning-base); padding: 0 1em 1em">
        If it's not working well, please submit an issue to us
      </div>
    </template>
  </re-popconfirm>
</template>

Disabled ​

Use disabled to disable Popconfirm.

vue
<template>
  <div>
    <re-popconfirm :disabled="disabled" width="200" title="Are you sure to delete this item?">
      <re-button type="danger" :disabled="disabled">
        {{ disabled ? 'Disabled' : 'Delete' }}
      </re-button>
    </re-popconfirm>
    <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<boolean>(false)

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

Extra Button Slot ​

Use slot#extra to provide extra buttons.

vue
<template>
  <re-popconfirm
    title="Sometimes we need some extra buttons"
    cancel-text="No"
    confirm-text="Yes"
    max-width="280"
  >
    <re-button>Extra Button</re-button>
    <template #extra>
      <re-button size="mini" type="primary">Or</re-button>
    </template>
  </re-popconfirm>
</template>

Customize Boundary ​

Use boundary and rootBoundary to set Popconfirm 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-popconfirm
          v-if="container1"
          v-model:visible="visible1"
          :boundary="container1"
          title="Scroll me to top boundary"
          width="200"
        >
          <re-button @click="visible1 = !visible1">boundary: container</re-button>
        </re-popconfirm>
        <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-popconfirm
          v-if="container2"
          v-model:visible="visible2"
          title="Scroll me to left boundary"
          width="200"
          :boundary="container2"
          placement="left"
        >
          <re-button @click="visible2 = !visible2">boundary: container</re-button>
        </re-popconfirm>
        <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-popconfirm v-model:visible="visible3" title="Scroll me to body top boundary" width="200">
        <re-button @click="visible3 = !visible3">rootBoundary: 'viewport'</re-button>
      </re-popconfirm>
      <div class="h-300px"></div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'

const visible1 = ref<boolean>(true)
const visible2 = ref<boolean>(true)
const visible3 = 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 Popconfirm 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-popconfirm
        v-model:visible="visible1"
        alt-boundary
        title="Scroll me to top boundary"
        width="200"
      >
        <re-button @click="visible1 = !visible1">altBoundary: true</re-button>
      </re-popconfirm>
      <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-popconfirm
        v-model:visible="visible2"
        title="Scroll me to left boundary"
        alt-boundary
        placement="left"
        width="200"
      >
        <re-button @click="visible2 = !visible2">altBoundary: true</re-button>
      </re-popconfirm>
      <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-popconfirm
        v-model:visible="visible3"
        element-context="reference"
        title="elementContext: 'reference'"
        width="200"
      >
        <re-button @click="visible3 = !visible3">Scroll me to top boundary</re-button>
      </re-popconfirm>
      <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-popconfirm
        v-model:visible="visible4"
        title="elementContext: 'reference'"
        element-context="reference"
        placement="left"
        width="200"
      >
        <re-button @click="visible4 = !visible4">Scroll me to left boundary</re-button>
      </re-popconfirm>
      <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-popconfirm
        v-model:visible="visible5"
        alt-boundary
        :flip-options="{ fallbackPlacements: ['top', 'right', 'bottom'] }"
        title="Scroll me to top boundary"
        width="200"
      >
        <re-button class="mr-15em" @click="visible5 = !visible5">altBoundary: true</re-button>
      </re-popconfirm>
      <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-popconfirm
        v-model:visible="visible6"
        title="Scroll me to left boundary"
        alt-boundary
        :flip-options="{ fallbackPlacements: ['top', 'right', 'bottom'] }"
        placement="left"
        width="200"
      >
        <re-button @click="visible6 = !visible6">altBoundary: true</re-button>
      </re-popconfirm>
      <div class="w-500px shrink-0"></div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'

const visible1 = ref<boolean>(true)
const visible2 = ref<boolean>(true)
const visible3 = ref<boolean>(true)
const visible4 = ref<boolean>(true)
const visible5 = ref<boolean>(true)
const visible6 = 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 the Popconfirm.

Basic External Trigger Reference

Multiple External Trigger References for singleton

vue
<template>
  <p>Basic External Trigger Reference</p>
  <re-popconfirm
    is-external
    :external-ref="externalRef"
    title="Do you want to use a external element for reference?"
    width="200"
  ></re-popconfirm>
  <re-button ref="buttonRef" @click="setExternal">Click me</re-button>

  <p>Multiple External Trigger References for singleton</p>
  <re-popconfirm
    trigger="hover"
    title="Will you use me during hover?"
    width="200"
    is-external
    :external-ref="hoverRef"
  ></re-popconfirm>
  <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-popconfirm
    title="Have you encountered multiple references but only one floating layer?"
    width="280"
    is-external
    :external-ref="clickRef"
  ></re-popconfirm>
  <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-popconfirm
    :visible="visible"
    is-virtual
    :virtual-ref="virtualRef"
    width="200"
    title="Virtual Element is usually a object with getBoundingClientRect method"
  ></re-popconfirm>
  <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 Popconfirm
vue
<template>
  <re-popconfirm
    :visible="visible"
    is-virtual
    :virtual-ref="rangeRef"
    width="200"
    title="Sometimes we interact with text"
  ></re-popconfirm>
  <span ref="textRef">Select the text to visible the Popconfirm</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 = () => {
  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) // mobile
  document.addEventListener('selectionchange', selectionChange)
})

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

Popconfirm Attributes ​

NameDescriptionTypeDefault
placementPopconfirm positionenumtop
triggerThe trigger event nameenumclick
titlePopconfirm titlestring''
iconPopconfirm iconstring | Componenthelp
show-iconWhether to show Popconfirm iconbooleantrue
cancel-textCancel button textstringNo
cancel-typeCancel button typeenum—
cancel-sizeCancel button size'large' | 'small' | 'mini'mini
confirm-textConfirm button textstringYes
confirm-typeConfirm button typeenumprimary
confirm-sizeConfirm button size'large' | 'small' | 'mini'mini
contentPopconfirm contentstring''
is-htmlWhether content is treated as HTML stringboolean—
disabledWhether Popconfirm is disabledboolean—
visible / v-model:visibleWhether Popconfirm is visibleboolean—
offsetOffset from the reference edge. See Floating UI OffsetOptions for detailsnumber | interface10
widthPopconfirm widthnumber | string—
heightPopconfirm heightnumber | string—
max-widthPopconfirm max widthnumber | string—
max-heightPopconfirm max heightnumber | string—
themePopconfirm theme'dark' |'light'light
reverse-themewhether to reverse Popconfirm theme colorbooleanfalse
append-toTarget element for appending PopconfirmcssSelector | HTMLElementbody
teleportedWhether to teleport Popconfirm 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 Popconfirm appears , but not effective when visible is present or is-virtual or is-externalnumber0
hide-delayDelay(ms) before Popconfirm disappears , but not effective when visible is present or is-virtual or is-externalnumber200
show-arrowWhether to show arrow for Popconfirmbooleantrue
arrow-sizeThe arrow sizenumber8
arrow-offsetPadding between the arrow and the Popconfirm edgenumber4
arrow-optionsFloating UI ArrowOptions Parametersinterface—
transitionName of Vue3 Transition component for customize transitionstringpopconfirm
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 outnumber0
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—

Popconfirm 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
cancelTriggered when cancel button is clickedFunction
confirmTriggered when confirm button is clickedFunction

Popconfirm Slots ​

NameDescriptionSlot Props
defaultCustomize default reference—
headerCustomize headerinterface
iconCustomize header iconinterface
titleCustomize header titleinterface
contentCustomize contentinterface
footerCustomize footerinterface
cancelCustomize footer cancel buttoninterface
confirmCustomize footer confirm buttoninterface
extraAdd footer extra buttoninterface

Popconfirm Exposes ​

NameDescriptionType
tooltipRefThe instance of Tooltip elementHTMLElement
cancelTrigger cancel eventFunction
confirmTrigger confirm eventFunction

MIT License