Demos
How to import
<script setup lang="ts">
import { Popconfirm } from '@fibrous/semi-ui-vue';
</script>
Basic Usage
Popconfirm is based on the Tooltip component. Children support the same type as Tooltip. For details, please refer to Tooltip Cautions
Code
<script setup lang="ts">
import { Button, Popconfirm, Toast } from '@fibrous/semi-ui-vue';
const onConfirm = () => {
Toast.success('确认保存!');
};
const onCancel = () => {
Toast.warning('取消保存!');
};
</script>
<template>
<Popconfirm @cancel="onCancel" @confirm="onConfirm">
<Button>保存</Button>
<template #title>确定是否要保存此修改?</template>
<template #content>此修改将不可逆</template>
</Popconfirm>
</template>Type collocation
Developers can use scenario-based okType/cancelType and the #icon slot to match different styles of bubble confirmation boxes. Without an #icon slot the default warning icon is shown; an empty #icon slot renders no icon.
Code
<script setup lang="ts">
import { ref } from 'vue';
import { IconAlertTriangle } from '@fibrous/semi-icons-vue';
import { Button, Popconfirm, Radio, RadioGroup, type RadioValue } from '@fibrous/semi-ui-vue';
type TypeKey = 'default' | 'warning' | 'danger' | 'tertiary';
const typeMap: Record<TypeKey, { okType?: 'danger'; color?: string }> = {
default: {},
warning: { color: 'var(--semi-color-warning)' },
danger: { okType: 'danger', color: 'var(--semi-color-danger)' },
tertiary: { color: 'var(--semi-color-tertiary)' },
};
const keys = Object.keys(typeMap) as TypeKey[];
const type = ref<TypeKey>('default');
const visible = ref(true);
const changeType = (value: RadioValue | undefined) => {
const key = keys.find((item) => item === value);
if (key) type.value = key;
};
</script>
<template>
<div>
<RadioGroup :modelValue="type" :style="{ marginTop: '14px', marginBottom: '14px' }" type="button" @update:modelValue="changeType">
<Radio v-for="key in keys" :key="key" :value="key">
<span :style="{ color: `var(--semi-color-${key === 'default' ? 'primary' : key})` }">{{ key }}</span>
</Radio>
</RadioGroup>
<div>
<Popconfirm v-model:visible="visible" :okType="typeMap[type].okType" trigger="custom">
<Button @click="visible = !visible">点击此处</Button>
<template #icon>
<IconAlertTriangle size="extra-large" :style="{ color: typeMap[type].color }" />
</template>
<template #title>确定是否要保存此修改?</template>
<template #content>此修改将不可逆</template>
</Popconfirm>
</div>
</div>
</template>Delay hide
onConfirm and onCancel can be closed after click through return Promise.
When onCancel and onConfirm are triggered, the corresponding Button will automatically switch to loading: true
promise solve will close the bubble confirmation box, the bubble will remain when promise reject, and button loading will automatically switch to false
Code
<script setup lang="ts">
import { Button, Popconfirm } from '@fibrous/semi-ui-vue';
const onConfirm = () =>
new Promise<void>((resolve) => {
setTimeout(() => {
console.log('resolve,close popconfirm');
resolve();
}, 2000);
});
const onCancel = () =>
new Promise<void>((_resolve, reject) => {
setTimeout(() => {
console.log('reject, popconfirm still exist');
reject();
}, 2000);
});
</script>
<template>
<Popconfirm @cancel="onCancel" @confirm="onConfirm">
<Button>保存</Button>
<template #title>确定是否要保存此修改?</template>
<template #content>此修改将不可逆</template>
</Popconfirm>
</template>Initialize the Focus Position of Popup Layer
okButtonProps and cancelButtonProps support passing in the autoFocus parameter, which will automatically focus at this position when the panel is opened.
The #content slot receives { initialFocusRef } as its scope. Bind it to the focusable DOM or component with :ref, and it will automatically focus at this position when the panel is opened. When a button autoFocus and initialFocusRef are both given, the button wins.
Code
<script setup lang="ts">
import { Button, Popconfirm, Space } from '@fibrous/semi-ui-vue';
</script>
<template>
<Space>
<Popconfirm :okButtonProps="{ autoFocus: true, type: 'danger' }">
<Button>确认聚焦</Button>
<template #title>确定是否要保存此修改?</template>
<template #content>此修改将不可逆</template>
</Popconfirm>
<Popconfirm :cancelButtonProps="{ autoFocus: true }">
<Button>取消聚焦</Button>
<template #title>确定是否要保存此修改?</template>
<template #content>此修改将不可逆</template>
</Popconfirm>
<Popconfirm>
<Button>内容聚焦</Button>
<template #title>确定是否要保存此修改?</template>
<template #content="{ initialFocusRef }">
<input :ref="initialFocusRef" placeholder="focus here" />
</template>
</Popconfirm>
</Space>
</template>Use with Tooltip or Popover
Please refer to Use with Tooltip/Popover
API Reference
Props
| Property | Description | Type | Default |
|---|---|---|---|
| cancelButtonProps | Props of the cancel button. autoFocus focuses it on open; class and style land on the button. | PopconfirmButtonProps | semiGlobalDefault("Popconfirm", "cancelButtonProps") |
| cancelText | Cancel button text. Defaults to the locale entry Popconfirm.cancel. | string | semiGlobalDefault("Popconfirm", "cancelText") |
| cancelType | Type of the cancel button. | Type | semiDefault("Popconfirm", "cancelType", "tertiary") |
| defaultVisible | Whether it is initially shown when uncontrolled. | boolean | semiGlobalDefault("Popconfirm", "defaultVisible") |
| disabled | Whether it is disabled. A disabled Popconfirm renders only the trigger and never opens. | boolean | semiDefault("Popconfirm", "disabled", false) |
| okButtonProps | Props of the confirm button. autoFocus focuses it on open; class and style land on the button. | PopconfirmButtonProps | semiGlobalDefault("Popconfirm", "okButtonProps") |
| okText | Confirm button text. Defaults to the locale entry Popconfirm.confirm. | string | semiGlobalDefault("Popconfirm", "okText") |
| okType | Type of the confirm button. | Type | semiDefault("Popconfirm", "okType", "primary") |
| showCloseIcon | Whether the close button in the corner is shown. | boolean | semiDefault("Popconfirm", "showCloseIcon", true) |
| title | Plain-text title, which also names the dialog. The #title slot wins when both are given. It is a declared prop, so it never lands on an element as the native title attribute. | string | undefined |
| onCancel | Called when the cancel or close button is clicked. A returned Promise keeps the button loading and closes the card once it resolves; a rejection keeps it open. This remains a function prop so its result can be read. | Type((event: MouseEvent) => void | Promise<unknown>) | undefined |
| onConfirm | Called when the confirm button is clicked. A returned Promise keeps the button loading and closes the card once it resolves; a rejection keeps it open. This remains a function prop so its result can be read. | Type((event: MouseEvent) => void | Promise<unknown>) | undefined |
| ariaLabel | aria-label of the dialog. When given, it takes precedence over the title. | string | semiGlobalDefault("Popconfirm", "ariaLabel") |
| ariaLabelledby | aria-labelledby of the dialog. Defaults to the title, or to the content without a title. | string | semiGlobalDefault("Popconfirm", "ariaLabelledby") |
| ariaDescribedby | aria-describedby of the dialog. Defaults to the content when there are both a title and content. | string | semiGlobalDefault("Popconfirm", "ariaDescribedby") |
| role | ARIA role of the popup. Defaults to dialog. | string | semiDefault("Popconfirm", "role", "dialog") |
| autoAdjustOverflow | Whether the popup flips automatically when it would be clipped. | boolean | semiGlobalDefault("Popconfirm", "autoAdjustOverflow") |
| visible | Whether it is shown, used with v-model:visible. When given, this value decides; trigger keeps its value and the trigger events still work. | boolean | semiGlobalDefault("Popconfirm", "visible") |
| position | Popup position. Defaults to bottomLeft (bottomRight in RTL). | Type"top" | "bottom" | "left" | "right" | "topLeft" | "topRight" | "leftTop" | "leftBottom" | "rightTop" | "rightBottom" | "bottomLeft" | "bottomRight" | "leftTopOver" | "rightTopOver" | "leftBottomOver" | "rightBottomOver" | semiGlobalDefault("Popconfirm", "position") |
| motion | Whether the popup is animated. | boolean | semiGlobalDefault("Popconfirm", "motion") |
| mouseEnterDelay | Milliseconds before it shows after the pointer enters. Applies to the hover and focus triggers. | number | semiGlobalDefault("Popconfirm", "mouseEnterDelay") |
| mouseLeaveDelay | Milliseconds before it hides after the pointer leaves. Applies to the hover and focus triggers. | number | semiGlobalDefault("Popconfirm", "mouseLeaveDelay") |
| trigger | When it shows: hover, focus, click, contextMenu or custom. | "hover" | "focus" | "click" | "custom" | "contextMenu" | semiDefault("Popconfirm", "trigger", "click") |
| contentClassName | Class name of the content container. | string | unknown[] | semiGlobalDefault("Popconfirm", "contentClassName") |
| showArrow | Whether the arrow is shown. | boolean | semiGlobalDefault("Popconfirm", "showArrow") |
| spacing | Distance in pixels between the popup and the trigger. An object sets the horizontal and vertical distances. | number | { x: number; y: number; } | semiGlobalDefault("Popconfirm", "spacing") |
| stopPropagation | Whether click, mousedown and focus in/out events on the popup stop propagating. Clicks inside the card never propagate. | string | boolean | semiDefault("Popconfirm", "stopPropagation", true) |
| arrowStyle | Border color, background color and border opacity of the arrow. | ArrowStyle | semiGlobalDefault("Popconfirm", "arrowStyle") |
| arrowPointAtCenter | Whether the arrow points at the center of the trigger. Requires showArrow. | boolean | semiGlobalDefault("Popconfirm", "arrowPointAtCenter") |
| prefixCls | Class prefix of the confirmation card. | string | semiDefault("Popconfirm", "prefixCls", cssClasses.PREFIX) |
| closeOnEsc | Whether Esc closes the open card. With trigger custom it only emits escKeyDown and the caller decides whether to close. | boolean | semiGlobalDefault("Popconfirm", "closeOnEsc") |
| guardFocus | Whether Tab cycles inside the card while focus is in it. | boolean | semiGlobalDefault("Popconfirm", "guardFocus") |
| returnFocusOnClose | Whether focus returns to the trigger after closing. It also works with a controlled visible, and has no effect with trigger custom. | boolean | semiGlobalDefault("Popconfirm", "returnFocusOnClose") |
| clickToHide | Whether a click on the popup or anything inside it closes it. | boolean | semiGlobalDefault("Popconfirm", "clickToHide") |
| disableArrowKeyDown | Whether the arrow keys on the trigger are prevented from moving focus into the card. | boolean | semiGlobalDefault("Popconfirm", "disableArrowKeyDown") |
| disableFocusListener | Whether keyboard focus is ignored when trigger is hover. | boolean | semiGlobalDefault("Popconfirm", "disableFocusListener") |
| keepDOM | Whether the content stays mounted while closed. | boolean | semiGlobalDefault("Popconfirm", "keepDOM") |
| condition | Whether it may be triggered. Only an explicit false disables the hover, click and focus triggers. Changing it from true to false closes an open card at once; with a controlled visible it only emits update:visible and visibleChange(false), and the card closes once the caller writes back. | boolean | semiGlobalDefault("Popconfirm", "condition") |
Events
| Event | Description | Callback parameters |
|---|---|---|
| open | Emitted once per opening when the card is shown, as its enter animation starts, before afterOpen, controlled or not; not emitted for a hover open withdrawn because the pointer already left. | [] |
| update:visible | Emitted when it should show or hide, for v-model:visible to write back. | [visible: boolean] |
| visibleChange | Emitted when the visibility changes. After a click on the trigger it fires before the card appears. With a controlled visible it reports only requests from user interaction, not changes the parent makes to visible. | [visible: boolean] |
| clickOutSide | Emitted when the mouse is pressed outside of the trigger and the open card. Only for trigger click, contextMenu or custom. | [event: MouseEvent] |
| escKeyDown | Emitted when Esc is pressed while the card is open and closeOnEsc is true (the default). | [event: KeyboardEvent] |
| afterOpen | Emitted after the card has opened and its enter animation has finished, or right after opening when there is no enter animation, controlled or not; not emitted for an open that is closed before the enter animation ends. | [] |
| afterClose | Emitted after the card has closed and its leave animation has finished. | [] |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| default | The trigger. | any |
| title | Title of the card. | any |
| content | Content of the card. The scope parameter initialFocusRef binds to the element that receives focus on open. An empty slot renders no content area. | TypeRenderContentProps<FocusTarget> |
| icon | Custom icon. The default warning icon shows when omitted; an empty slot renders no icon. | any |
Exposes
| Name | Description | Type |
|---|---|---|
| focusTrigger | Focuses the trigger. Only works when returnFocusOnClose is true and trigger is not custom; does nothing when disabled. | Type() => void |
class and style land on the confirmation card, and the class and style in okButtonProps and cancelButtonProps land on the buttons; other undeclared attributes are discarded. aria-label, aria-labelledby and aria-describedby are declared props and land on the role="dialog" element. When the subtree is cached by <KeepAlive> (deactivated), the popup is treated as closed and update:visible and visibleChange are emitted with false; a popup whose visible is one-way bound to true is hidden with the cached subtree and shows again once reactivated.
When visible is controlled, clicking or hovering the trigger emits update:visible and visibleChange for the caller to write back with v-model:visible; changes the parent makes to visible itself emit neither, and returnFocusOnClose works as usual. With a one-way :visible and no write-back, confirming or cancelling does not return focus to the trigger at once; focus goes back when the card has really closed.
Accessibility
ARIA
- Whatever the trigger,
hoverandfocusincluded, the Popconfirm popup has roledialog, named bytitle(bycontentwhen there is notitle); theroleprop overrides it - For the rest, please refer to Popover
Keyboard and focus
- Popconfirm must have trigger, trigger can be focused, use
Enterkey to open Popconfirm - After Popconfirm is activated, press the arrow key ⬇️ to move the focus to Popconfirm. The initial focus of Popconfirm should follow several principles:
- If the Popconfirm contains the last step of an irreversible process, such as: deleting data, etc., then this initial focus is preferably on the least destructive interactable element, such as: the cancel button (by passing the
autoFocusto the objectcancelButtonProps) - If you only read text in Popconfirm, it is recommended to set the initial focus on the most likely interactive elements, such as: confirm button (implemented by passing
autoFocusto the objectokButtonProps)
- If the Popconfirm contains the last step of an irreversible process, such as: deleting data, etc., then this initial focus is preferably on the least destructive interactable element, such as: the cancel button (by passing the
- Keyboard users can dismiss Popconfirm by pressing
Escand focus should return to the trigger. After the user closes the Pop through the interactive element within the Popconfirm, the focus should also return to the trigger (except when trigger iscustom) - When it is opened, after the user clicks
Escin the blank space in Popconfirm, the focus will also return to the trigger (except when trigger iscustom)
Design Tokens
| Sass variable | Value | Usage |
|---|---|---|
| $color-popconfirm_header-text | var(--semi-color-text-0) | 标题文字颜色 |
| $color-popconfirm_body-text | var(--semi-color-text-2) | 正文文字颜色 |
| $color-popconfirm_header_alert-icon | var(--semi-color-warning) | 警示图标颜色 |
| $width-popconfirm-icon | 24px | 图标宽度 |
| $width-popconfirm-maxWidth | 400px | 整体最大宽度 |
| $spacing-popconfirm-top | 24px | 顶部内边距 |
| $spacing-popconfirm-bottom | 20px | 底部内边距 |
| $spacing-popconfirm_with_arrow-padding | 12px | 顶部内边距 |
| $spacing-popconfirm_header_title-marginBottom | 8px | header 标题底部外边距 |
| $spacing-popconfirm_body_p-padding | 0 | body 正文内边距 |
| $spacing-popconfirm_body_p-margin | 0 | body 正文外边距 |
| $spacing-popconfirm_footer-marginTop | 25px | footer 顶部外边距 |
| $spacing-popconfirm_footer_btn-marginRight | 8px | footer 按钮右侧外边距 |
| $spacing-popconfirm_popover_with_arrow_inner-padding | ($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-bottom - $spacing-popconfirm_with_arrow-padding) | 带三角形箭头时的内边距 |
| $spacing-popconfirm_popover_with_arrow_inner_rtl-padding | ($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-bottom - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding) | 带三角形箭头时的内边距(rtl) |
| $spacing-popconfirm_header_icon-marginRight | 12px | header 图标的右侧外边距 |
| $font-popconfirm_header_title-fontWeight | $font-weight-bold | header 标题字重 |
| $radius-popconfirm-popover | var(--semi-border-radius-medium) | 气泡确认框圆角大小 |
FAQ
-
Why does the Popconfirm floating layer lose its width and wrap unexpectedly when the width is not enough near the screen border?
After Chromium 104, the wrapping rendering strategy when the width of the screen border text is not enough has changed. For details, see issue #1022, the semi-side has been This problem was fixed in v2.17.0.