diff --git a/app/components/chat-list.tsx b/app/components/chat-list.tsx
index fc4e5378..a6143f32 100644
--- a/app/components/chat-list.tsx
+++ b/app/components/chat-list.tsx
@@ -17,6 +17,7 @@ import { Path } from "../constant";
 import { MaskAvatar } from "./mask";
 import { Mask } from "../store/mask";
 import { useRef, useEffect } from "react";
+import { showConfirm } from "./ui-lib";
 
 export function ChatItem(props: {
   onClick?: () => void;
@@ -139,8 +140,11 @@ export function ChatList(props: { narrow?: boolean }) {
                   navigate(Path.Chat);
                   selectSession(i);
                 }}
-                onDelete={() => {
-                  if (!props.narrow || confirm(Locale.Home.DeleteChat)) {
+                onDelete={async () => {
+                  if (
+                    !props.narrow ||
+                    (await showConfirm(Locale.Home.DeleteChat))
+                  ) {
                     chatStore.deleteSession(i);
                   }
                 }}
diff --git a/app/components/chat.tsx b/app/components/chat.tsx
index 6db5eb2b..fd732b9d 100644
--- a/app/components/chat.tsx
+++ b/app/components/chat.tsx
@@ -61,7 +61,7 @@ import Locale from "../locales";
 import { IconButton } from "./button";
 import styles from "./chat.module.scss";
 
-import { ListItem, Modal, showToast } from "./ui-lib";
+import { ListItem, Modal, showConfirm, showToast } from "./ui-lib";
 import { useLocation, useNavigate } from "react-router-dom";
 import { LAST_INPUT_KEY, Path, REQUEST_TIMEOUT_MS } from "../constant";
 import { Avatar } from "./emoji";
@@ -93,8 +93,8 @@ export function SessionConfigModel(props: { onClose: () => void }) {
             icon={<ResetIcon />}
             bordered
             text={Locale.Chat.Config.Reset}
-            onClick={() => {
-              if (confirm(Locale.Memory.ResetConfirm)) {
+            onClick={async () => {
+              if (await showConfirm(Locale.Memory.ResetConfirm)) {
                 chatStore.updateCurrentSession(
                   (session) => (session.memoryPrompt = ""),
                 );
diff --git a/app/components/error.tsx b/app/components/error.tsx
index 0e01c417..33abe931 100644
--- a/app/components/error.tsx
+++ b/app/components/error.tsx
@@ -5,6 +5,7 @@ import ResetIcon from "../icons/reload.svg";
 import { ISSUE_URL } from "../constant";
 import Locale from "../locales";
 import { downloadAs } from "../utils";
+import { showConfirm } from "./ui-lib";
 
 interface IErrorBoundaryState {
   hasError: boolean;
@@ -57,10 +58,13 @@ export class ErrorBoundary extends React.Component<any, IErrorBoundaryState> {
             <IconButton
               icon={<ResetIcon />}
               text="Clear All Data"
-              onClick={() =>
-                confirm(Locale.Settings.Actions.ConfirmClearAll) &&
-                this.clearAndSaveData()
-              }
+              onClick={async () => {
+                if (
+                  await showConfirm(Locale.Settings.Actions.ConfirmClearAll)
+                ) {
+                  this.clearAndSaveData();
+                }
+              }}
               bordered
             />
           </div>
diff --git a/app/components/mask.tsx b/app/components/mask.tsx
index d48ed7c2..c10ba476 100644
--- a/app/components/mask.tsx
+++ b/app/components/mask.tsx
@@ -15,7 +15,15 @@ import CopyIcon from "../icons/copy.svg";
 import { DEFAULT_MASK_AVATAR, Mask, useMaskStore } from "../store/mask";
 import { ChatMessage, ModelConfig, useAppConfig, useChatStore } from "../store";
 import { ROLES } from "../client/api";
-import { Input, List, ListItem, Modal, Popover, Select } from "./ui-lib";
+import {
+  Input,
+  List,
+  ListItem,
+  Modal,
+  Popover,
+  Select,
+  showConfirm,
+} from "./ui-lib";
 import { Avatar, AvatarPicker } from "./emoji";
 import Locale, { AllLangs, ALL_LANG_OPTIONS, Lang } from "../locales";
 import { useNavigate } from "react-router-dom";
@@ -125,10 +133,10 @@ export function MaskConfig(props: {
             <input
               type="checkbox"
               checked={props.mask.syncGlobalConfig}
-              onChange={(e) => {
+              onChange={async (e) => {
                 if (
                   e.currentTarget.checked &&
-                  confirm(Locale.Mask.Config.Sync.Confirm)
+                  (await showConfirm(Locale.Mask.Config.Sync.Confirm))
                 ) {
                   props.updateMask((mask) => {
                     mask.syncGlobalConfig = e.currentTarget.checked;
@@ -439,8 +447,8 @@ export function MaskPage() {
                     <IconButton
                       icon={<DeleteIcon />}
                       text={Locale.Mask.Item.Delete}
-                      onClick={() => {
-                        if (confirm(Locale.Mask.Item.DeleteConfirm)) {
+                      onClick={async () => {
+                        if (await showConfirm(Locale.Mask.Item.DeleteConfirm)) {
                           maskStore.delete(m.id);
                         }
                       }}
diff --git a/app/components/new-chat.tsx b/app/components/new-chat.tsx
index 30041c5c..64c4703a 100644
--- a/app/components/new-chat.tsx
+++ b/app/components/new-chat.tsx
@@ -14,6 +14,7 @@ import Locale from "../locales";
 import { useAppConfig, useChatStore } from "../store";
 import { MaskAvatar } from "./mask";
 import { useCommand } from "../command";
+import { showConfirm } from "./ui-lib";
 
 function getIntersectionArea(aRect: DOMRect, bRect: DOMRect) {
   const xmin = Math.max(aRect.x, bRect.x);
@@ -125,8 +126,8 @@ export function NewChat() {
         {!state?.fromHome && (
           <IconButton
             text={Locale.NewChat.NotShow}
-            onClick={() => {
-              if (confirm(Locale.NewChat.ConfirmNoShow)) {
+            onClick={async () => {
+              if (await showConfirm(Locale.NewChat.ConfirmNoShow)) {
                 startChat();
                 config.update(
                   (config) => (config.dontShowMaskSplashScreen = true),
diff --git a/app/components/settings.tsx b/app/components/settings.tsx
index 1d45a0c6..54389c9b 100644
--- a/app/components/settings.tsx
+++ b/app/components/settings.tsx
@@ -18,6 +18,7 @@ import {
   PasswordInput,
   Popover,
   Select,
+  showConfirm,
 } from "./ui-lib";
 import { ModelConfigList } from "./model-config";
 
@@ -377,8 +378,10 @@ export function Settings() {
           <div className="window-action-button">
             <IconButton
               icon={<ClearIcon />}
-              onClick={() => {
-                if (confirm(Locale.Settings.Actions.ConfirmClearAll)) {
+              onClick={async () => {
+                if (
+                  await showConfirm(Locale.Settings.Actions.ConfirmClearAll)
+                ) {
                   chatStore.clearAllData();
                 }
               }}
@@ -389,8 +392,10 @@ export function Settings() {
           <div className="window-action-button">
             <IconButton
               icon={<ResetIcon />}
-              onClick={() => {
-                if (confirm(Locale.Settings.Actions.ConfirmResetAll)) {
+              onClick={async () => {
+                if (
+                  await showConfirm(Locale.Settings.Actions.ConfirmResetAll)
+                ) {
                   resetConfig();
                 }
               }}
diff --git a/app/components/sidebar.tsx b/app/components/sidebar.tsx
index 038ca86f..d9d861d5 100644
--- a/app/components/sidebar.tsx
+++ b/app/components/sidebar.tsx
@@ -26,7 +26,7 @@ import {
 import { Link, useNavigate } from "react-router-dom";
 import { useMobileScreen } from "../utils";
 import dynamic from "next/dynamic";
-import { showToast } from "./ui-lib";
+import { showConfirm, showToast } from "./ui-lib";
 
 const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
   loading: () => null,
@@ -160,8 +160,8 @@ export function SideBar(props: { className?: string }) {
           <div className={styles["sidebar-action"] + " " + styles.mobile}>
             <IconButton
               icon={<CloseIcon />}
-              onClick={() => {
-                if (confirm(Locale.Home.DeleteChat)) {
+              onClick={async () => {
+                if (await showConfirm(Locale.Home.DeleteChat)) {
                   chatStore.deleteSession(chatStore.currentSessionIndex);
                 }
               }}
diff --git a/app/components/ui-lib.tsx b/app/components/ui-lib.tsx
index be9b30a6..156eecfa 100644
--- a/app/components/ui-lib.tsx
+++ b/app/components/ui-lib.tsx
@@ -4,6 +4,7 @@ import CloseIcon from "../icons/close.svg";
 import EyeIcon from "../icons/eye.svg";
 import EyeOffIcon from "../icons/eye-off.svg";
 import DownIcon from "../icons/down.svg";
+import Locale from "../locales";
 
 import { createRoot } from "react-dom/client";
 import React, { HTMLProps, useEffect, useState } from "react";
@@ -87,7 +88,7 @@ export function Loading() {
 
 interface ModalProps {
   title: string;
-  children?: JSX.Element | JSX.Element[];
+  children?: any;
   actions?: JSX.Element[];
   onClose?: () => void;
 }
@@ -262,3 +263,45 @@ export function Select(
     </div>
   );
 }
+
+export function showConfirm(content: any) {
+  const div = document.createElement("div");
+  div.className = "modal-mask";
+  document.body.appendChild(div);
+
+  const root = createRoot(div);
+  const closeModal = () => {
+    root.unmount();
+    div.remove();
+  };
+
+  return new Promise<boolean>((resolve) => {
+    root.render(
+      <Modal
+        title={Locale.UI.Confirm}
+        actions={[
+          <IconButton
+            key="cancel"
+            text={Locale.UI.Cancel}
+            onClick={() => {
+              resolve(false);
+              closeModal();
+            }}
+          ></IconButton>,
+          <IconButton
+            key="confirm"
+            text={Locale.UI.Confirm}
+            type="primary"
+            onClick={() => {
+              resolve(true);
+              closeModal();
+            }}
+          ></IconButton>,
+        ]}
+        onClose={closeModal}
+      >
+        {content}
+      </Modal>,
+    );
+  });
+}