diff --git a/src/components/profile/profile-new.tsx b/src/components/profile/profile-new.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..bd2a5e80c6d754dd96d7213533d9265415a2b53d
--- /dev/null
+++ b/src/components/profile/profile-new.tsx
@@ -0,0 +1,64 @@
+import { useState } from "react";
+import {
+  Button,
+  Dialog,
+  DialogActions,
+  DialogContent,
+  DialogTitle,
+  TextField,
+} from "@mui/material";
+import Notice from "../base/base-notice";
+
+interface Props {
+  open: boolean;
+  onClose: () => void;
+  onSubmit: (name: string, desc: string) => void;
+}
+
+const ProfileNew = (props: Props) => {
+  const { open, onClose, onSubmit } = props;
+  const [name, setName] = useState("");
+  const [desc, setDesc] = useState("");
+
+  const onCreate = () => {
+    if (!name.trim()) {
+      Notice.error("`Name` should not be null");
+      return;
+    }
+    onSubmit(name, desc);
+  };
+
+  return (
+    <Dialog open={open} onClose={onClose}>
+      <DialogTitle>Create Profile</DialogTitle>
+      <DialogContent sx={{ width: 320, pb: 0.5 }}>
+        <TextField
+          autoFocus
+          fullWidth
+          label="Name"
+          margin="dense"
+          variant="outlined"
+          value={name}
+          onChange={(e) => setName(e.target.value)}
+        />
+
+        <TextField
+          fullWidth
+          label="Descriptions"
+          margin="normal"
+          variant="outlined"
+          value={desc}
+          onChange={(e) => setDesc(e.target.value)}
+        />
+      </DialogContent>
+      <DialogActions sx={{ px: 2, pb: 2 }}>
+        <Button onClick={onClose}>Cancel</Button>
+        <Button onClick={onCreate} variant="contained">
+          Create
+        </Button>
+      </DialogActions>
+    </Dialog>
+  );
+};
+
+export default ProfileNew;
diff --git a/src/pages/profiles.tsx b/src/pages/profiles.tsx
index 299658a21993c64a2ffb332136dcedba87a6643f..3f75eb0138f7a515048960aba20b9a81b923daa3 100644
--- a/src/pages/profiles.tsx
+++ b/src/pages/profiles.tsx
@@ -10,9 +10,10 @@ import {
 } from "../services/cmds";
 import { getProxies, updateProxy } from "../services/api";
 import noop from "../utils/noop";
-import Notice from "../components/notice";
-import BasePage from "../components/base-page";
-import ProfileItem from "../components/profile-item";
+import Notice from "../components/base/base-notice";
+import BasePage from "../components/base/base-page";
+import ProfileItem from "../components/profile/profile-item";
+import ProfileNew from "../components/profile/profile-new";
 
 const ProfilePage = () => {
   const [url, setUrl] = useState("");
@@ -96,13 +97,15 @@ const ProfilePage = () => {
   };
 
   const lockNewRef = useRef(false);
-  const onNew = async () => {
+  const [dialogOpen, setDialogOpen] = useState(false);
+  const onNew = async (name: string, desc: string) => {
     if (lockNewRef.current) return;
     lockNewRef.current = true;
 
     try {
-      await newProfile("New Profile", "no desc");
+      await newProfile(name, desc);
       mutate("getProfiles");
+      setDialogOpen(false);
     } catch (err: any) {
       err && Notice.error(err.toString());
     } finally {
@@ -131,7 +134,7 @@ const ProfilePage = () => {
         >
           Import
         </Button>
-        <Button variant="contained" onClick={onNew}>
+        <Button variant="contained" onClick={() => setDialogOpen(true)}>
           New
         </Button>
       </Box>
@@ -148,6 +151,12 @@ const ProfilePage = () => {
           </Grid>
         ))}
       </Grid>
+
+      <ProfileNew
+        open={dialogOpen}
+        onClose={() => setDialogOpen(false)}
+        onSubmit={onNew}
+      />
     </BasePage>
   );
 };