diff --git a/src/components/notice.tsx b/src/components/notice.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..eedc7a549eaac7bc00e8582bc266d4f9f145112c
--- /dev/null
+++ b/src/components/notice.tsx
@@ -0,0 +1,88 @@
+import ReactDOM from "react-dom";
+import { ReactNode, useState } from "react";
+import { Box, IconButton, Slide, Snackbar, Typography } from "@mui/material";
+import { Close, CheckCircleRounded, ErrorRounded } from "@mui/icons-material";
+
+interface InnerProps {
+  type: string;
+  duration?: number;
+  message: ReactNode;
+  onClose: () => void;
+}
+
+const NoticeInner = (props: InnerProps) => {
+  const { type, message, duration = 2000, onClose } = props;
+  const [visible, setVisible] = useState(true);
+
+  const onBtnClose = () => {
+    setVisible(false);
+    onClose();
+  };
+  const onAutoClose = (_e: any, reason: string) => {
+    if (reason !== "clickaway") onBtnClose();
+  };
+
+  const msgElement =
+    type === "info" ? (
+      message
+    ) : (
+      <Box sx={{ display: "flex", alignItems: "center" }}>
+        {type === "error" && <ErrorRounded color="error" />}
+        {type === "success" && <CheckCircleRounded color="success" />}
+
+        <Typography sx={{ ml: 1 }}>{message}</Typography>
+      </Box>
+    );
+
+  return (
+    <Snackbar
+      open={visible}
+      anchorOrigin={{ vertical: "top", horizontal: "right" }}
+      autoHideDuration={duration}
+      onClose={onAutoClose}
+      message={msgElement}
+      sx={{ maxWidth: 360 }}
+      TransitionComponent={(p) => <Slide {...p} direction="left" />}
+      transitionDuration={200}
+      action={
+        <IconButton size="small" color="inherit" onClick={onBtnClose}>
+          <Close fontSize="inherit" />
+        </IconButton>
+      }
+    />
+  );
+};
+
+interface NoticeInstance {
+  (props: Omit<InnerProps, "onClose">): void;
+
+  info(message: ReactNode, duration?: number): void;
+  error(message: ReactNode, duration?: number): void;
+  success(message: ReactNode, duration?: number): void;
+}
+
+let parent: HTMLDivElement = null!;
+
+// @ts-ignore
+const Notice: NoticeInstance = (props) => {
+  if (!parent) {
+    parent = document.createElement("div");
+    document.body.appendChild(parent);
+  }
+
+  const container = document.createElement("div");
+  parent.appendChild(container);
+
+  const onUnmount = () => {
+    const result = ReactDOM.unmountComponentAtNode(container);
+    if (result && parent) parent.removeChild(container);
+  };
+
+  ReactDOM.render(<NoticeInner {...props} onClose={onUnmount} />, container);
+};
+
+(["info", "error", "success"] as const).forEach((type) => {
+  Notice[type] = (message, duration) => Notice({ type, message, duration });
+});
+
+export default Notice;
diff --git a/src/pages/profiles.tsx b/src/pages/profiles.tsx
index 57ef2d465162966c519c2f88edcd7946be1ef934..cbf8a3f0fe87085758e59915471b793fd221776d 100644
--- a/src/pages/profiles.tsx
+++ b/src/pages/profiles.tsx
@@ -9,14 +9,13 @@ import {
 } from "../services/cmds";
 import { getProxies, updateProxy } from "../services/api";
 import noop from "../utils/noop";
-import useNotice from "../utils/use-notice";
+import Notice from "../components/notice";
 import BasePage from "../components/base-page";
 import ProfileItemComp from "../components/profile-item";
 
 const ProfilePage = () => {
   const [url, setUrl] = useState("");
   const [disabled, setDisabled] = useState(false);
-  const [notice, noticeElement] = useNotice();
 
   const { mutate } = useSWRConfig();
   const { data: profiles = {} } = useSWR("getProfiles", getProfiles);
@@ -72,9 +71,9 @@ const ProfilePage = () => {
       await importProfile(url);
       mutate("getProfiles", getProfiles());
       if (!profiles.items?.length) selectProfile(0).catch(noop);
-      notice.success("Successfully import profile.");
+      Notice.success("Successfully import profile.");
     } catch {
-      notice.error("Failed to import profile.");
+      Notice.error("Failed to import profile.");
     } finally {
       setDisabled(false);
     }
@@ -108,7 +107,7 @@ const ProfilePage = () => {
           fullWidth
           value={url}
           onChange={(e) => setUrl(e.target.value)}
-          sx={{ mr: 4 }}
+          sx={{ mr: 2 }}
         />
         <Button
           disabled={!url || disabled}
@@ -131,8 +130,6 @@ const ProfilePage = () => {
           </Grid>
         ))}
       </Grid>
-
-      {noticeElement}
     </BasePage>
   );
 };
diff --git a/src/utils/use-notice.tsx b/src/utils/use-notice.tsx
deleted file mode 100644
index 26cab4ce25c5800be9f757c01aa9976e016f9977..0000000000000000000000000000000000000000
--- a/src/utils/use-notice.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import { useMemo, useState } from "react";
-import { Box, IconButton, Slide, Snackbar } from "@mui/material";
-import { Close, CheckCircleRounded, ErrorRounded } from "@mui/icons-material";
-
-interface NoticeInstance {
-  info: (msg: string) => void;
-  error: (msg: string) => void;
-  success: (msg: string) => void;
-}
-
-const useNotice = () => {
-  const [message, setMessage] = useState("");
-  const [level, setLevel] = useState<"info" | "error" | "success">("info");
-
-  const handleClose = (_e: any, reason: string) => {
-    if (reason !== "clickaway") setMessage("");
-  };
-
-  const msgElement =
-    level === "info" ? (
-      message
-    ) : (
-      <Box sx={{ display: "flex", alignItems: "center" }}>
-        {level === "error" && <ErrorRounded color="error" />}
-        {level === "success" && <CheckCircleRounded color="success" />}
-        <span style={{ marginLeft: 4 }}>{message}</span>
-      </Box>
-    );
-
-  const element = useMemo(
-    () => (
-      <Snackbar
-        open={!!message}
-        anchorOrigin={{ vertical: "top", horizontal: "right" }}
-        autoHideDuration={3000}
-        onClose={handleClose}
-        message={msgElement}
-        sx={{ maxWidth: 360 }}
-        TransitionComponent={(p) => <Slide {...p} direction="left" />}
-        transitionDuration={200}
-        action={
-          <IconButton
-            size="small"
-            color="inherit"
-            onClick={() => setMessage("")}
-          >
-            <Close fontSize="small" />
-          </IconButton>
-        }
-      />
-    ),
-    [message]
-  );
-
-  const instance = (Object.fromEntries(
-    (["info", "error", "success"] as const).map((item) => [
-      item,
-      (msg: string) => {
-        setLevel(item);
-        setMessage(msg);
-      },
-    ])
-  ) as unknown) as NoticeInstance;
-
-  return [instance, element] as const;
-};
-
-export default useNotice;