diff --git a/web/package.json b/web/package.json
index 6cdfc1596..22aa90523 100644
--- a/web/package.json
+++ b/web/package.json
@@ -144,6 +144,7 @@
     "react": "^17.0.1",
     "react-aspen": "^1.1.0",
     "react-dom": "^17.0.1",
+    "react-draggable": "^4.4.4",
     "react-select": "^4.2.1",
     "react-table": "^7.6.3",
     "react-virtualized-auto-sizer": "^1.0.6",
diff --git a/web/pgadmin/static/js/Theme/index.jsx b/web/pgadmin/static/js/Theme/index.jsx
index 08fbb758d..b9f9b1860 100644
--- a/web/pgadmin/static/js/Theme/index.jsx
+++ b/web/pgadmin/static/js/Theme/index.jsx
@@ -167,7 +167,7 @@ basicSettings = createMuiTheme(basicSettings, {
         top: 0,
         zIndex: 9999,
       }
-    }
+    },
   },
   transitions: {
     duration: {
@@ -199,6 +199,9 @@ basicSettings = createMuiTheme(basicSettings, {
     },
     MuiCheckbox: {
       disableTouchRipple: true,
+    },
+    MuiDialogTitle: {
+      disableTypography: true,
     }
   },
 });
@@ -390,6 +393,22 @@ function getFinalTheme(baseTheme) {
           color: baseTheme.palette.text.muted,
         },
       },
+      MuiDialogContent: {
+        root: {
+          padding: 0,
+          userSelect: 'text',
+        }
+      },
+      MuiDialogTitle: {
+        root: {
+          fontWeight: 'bold',
+          padding: '5px 10px',
+          cursor: 'move',
+          display: 'flex',
+          alignItems: 'center',
+          ...mixins.panelBorder.bottom,
+        }
+      },
     }
   }, baseTheme);
 }
diff --git a/web/pgadmin/static/js/components/Buttons.jsx b/web/pgadmin/static/js/components/Buttons.jsx
index 4c9c14b54..2554692dc 100644
--- a/web/pgadmin/static/js/components/Buttons.jsx
+++ b/web/pgadmin/static/js/components/Buttons.jsx
@@ -15,6 +15,12 @@ import CustomPropTypes from '../custom_prop_types';
 
 const useStyles = makeStyles((theme)=>({
   primaryButton: {
+    '&.MuiButton-outlinedSizeSmall': {
+      height: '28px',
+      '& .MuiSvgIcon-root': {
+        height: '0.8em',
+      }
+    },
     '&.Mui-disabled': {
       color: theme.palette.primary.contrastText,
       backgroundColor: theme.palette.primary.disabledMain,
@@ -28,6 +34,13 @@ const useStyles = makeStyles((theme)=>({
     backgroundColor: theme.palette.default.main,
     color: theme.palette.default.contrastText,
     border: '1px solid '+theme.palette.default.borderColor,
+    whiteSpace: 'nowrap',
+    '&.MuiButton-outlinedSizeSmall': {
+      height: '28px',
+      '& .MuiSvgIcon-root': {
+        height: '0.8em',
+      }
+    },
     '&.Mui-disabled': {
       color: theme.palette.default.disabledContrastText,
       borderColor: theme.palette.default.disabledBorderColor
@@ -52,35 +65,59 @@ const useStyles = makeStyles((theme)=>({
       backgroundColor: theme.custom.icon.hoverMain,
       color: theme.custom.icon.hoverContrastText,
     }
+  },
+  xsButton: {
+    padding: '2px 1px',
+    height: '24px',
+    '& .MuiSvgIcon-root': {
+      height: '0.8em',
+    }
+  },
+  noBorder: {
+    border: 0,
   }
 }));
 
 /* pgAdmin primary button */
 export const PrimaryButton = forwardRef((props, ref)=>{
-  let {children, className, ...otherProps} = props;
+  let {children, className, size, noBorder, ...otherProps} = props;
   const classes = useStyles();
-
+  let allClassName = [classes.primaryButton, className];
+  if(size == 'xs') {
+    size = undefined;
+    allClassName.push(classes.xsButton);
+  }
+  noBorder && allClassName.push(classes.noBorder);
   return (
-    <Button ref={ref} variant="contained" color="primary" className={clsx(classes.primaryButton, className)} {...otherProps}>{children}</Button>
+    <Button ref={ref} variant="contained" color="primary" size={size} className={clsx(allClassName)} {...otherProps}>{children}</Button>
   );
 });
 PrimaryButton.displayName = 'PrimaryButton';
 PrimaryButton.propTypes = {
+  size: PropTypes.string,
+  noBorder: PropTypes.bool,
   children: CustomPropTypes.children,
   className: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
 };
 
 /* pgAdmin default button */
 export const DefaultButton = forwardRef((props, ref)=>{
-  let {children, className, ...otherProps} = props;
+  let {children, className, size, noBorder, ...otherProps} = props;
   const classes = useStyles();
-
+  let allClassName = [classes.defaultButton, className];
+  if(size == 'xs') {
+    size = undefined;
+    allClassName.push(classes.xsButton);
+  }
+  noBorder && allClassName.push(classes.noBorder);
   return (
-    <Button ref={ref} variant="outlined" color="default" className={clsx(classes.defaultButton, className)} {...otherProps}>{children}</Button>
+    <Button ref={ref} variant="outlined" color="default" size={size} className={clsx(allClassName)} {...otherProps}>{children}</Button>
   );
 });
 DefaultButton.displayName = 'DefaultButton';
 DefaultButton.propTypes = {
+  size: PropTypes.string,
+  noBorder: PropTypes.bool,
   children: CustomPropTypes.children,
   className: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
 };
diff --git a/web/pgadmin/static/js/helpers/ModalProvider.jsx b/web/pgadmin/static/js/helpers/ModalProvider.jsx
new file mode 100644
index 000000000..c831760b0
--- /dev/null
+++ b/web/pgadmin/static/js/helpers/ModalProvider.jsx
@@ -0,0 +1,92 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2021, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import { Box, Dialog, DialogContent, DialogTitle, Paper } from '@material-ui/core';
+import React from 'react';
+import {getEpoch} from 'sources/utils';
+import { PgIconButton } from '../components/Buttons';
+import Draggable from 'react-draggable';
+import CloseIcon from '@material-ui/icons/CloseRounded';
+import CustomPropTypes from '../custom_prop_types';
+import PropTypes from 'prop-types';
+
+const ModalContext = React.createContext({});
+
+export function useModal() {
+  return React.useContext(ModalContext);
+}
+
+export default function ModalProvider({children}) {
+  const [modals, setModals] = React.useState([]);
+
+  const showModal = (title, content, modalOptions)=>{
+    let id = getEpoch().toString() + Math.random();
+    setModals((prev)=>[...prev, {
+      id: id,
+      title: title,
+      content: content,
+      ...modalOptions,
+    }]);
+  };
+  const closeModal = (id)=>{
+    setModals((prev)=>{
+      return prev.filter((o)=>o.id!=id);
+    });
+  };
+  const modalContext = React.useMemo(()=>({
+    showModal: showModal,
+    closeModal: closeModal,
+  }), []);
+  return (
+    <ModalContext.Provider value={modalContext}>
+      {children}
+      {modals.map((modalOptions, i)=>(
+        <ModalContainer key={i} {...modalOptions}/>
+      ))}
+    </ModalContext.Provider>
+  );
+}
+
+ModalProvider.propTypes = {
+  children: CustomPropTypes.children,
+};
+
+function PaperComponent(props) {
+  return (
+    <Draggable cancel={'[class*="MuiDialogContent-root"]'}>
+      <Paper {...props} style={{minWidth: '600px'}} />
+    </Draggable>
+  );
+}
+
+function ModalContainer({id, title, content}) {
+  let useModalRef = useModal();
+  let closeModal = ()=>useModalRef.closeModal(id);
+  return (
+    <Dialog
+      open={true}
+      onClose={closeModal}
+      PaperComponent={PaperComponent}
+      disableBackdropClick
+    >
+      <DialogTitle>
+        <Box marginRight="0.25rem">{title}</Box>
+        <Box marginLeft="auto"><PgIconButton icon={<CloseIcon />} size="xs" noBorder onClick={closeModal}/></Box>
+      </DialogTitle>
+      <DialogContent>
+        {content(closeModal)}
+      </DialogContent>
+    </Dialog>
+  );
+}
+ModalContainer.propTypes = {
+  id: PropTypes.string,
+  title: CustomPropTypes.children,
+  content: CustomPropTypes.children,
+};
diff --git a/web/pgadmin/static/js/helpers/Notifier.jsx b/web/pgadmin/static/js/helpers/Notifier.jsx
index 749c55ce6..98b8848fc 100644
--- a/web/pgadmin/static/js/helpers/Notifier.jsx
+++ b/web/pgadmin/static/js/helpers/Notifier.jsx
@@ -16,30 +16,54 @@ import CustomPropTypes from '../custom_prop_types';
 import gettext from 'sources/gettext';
 import pgWindow from 'sources/window';
 import Alertify from 'pgadmin.alertifyjs';
+import ModalProvider, { useModal } from './ModalProvider';
+import { DefaultButton, PrimaryButton } from '../components/Buttons';
+import { Box } from '@material-ui/core';
+import { makeStyles } from '@material-ui/styles';
+import HTMLReactParse from 'html-react-parser';
+import CloseIcon from '@material-ui/icons/CloseRounded';
+import CheckRoundedIcon from '@material-ui/icons/CheckRounded';
+import PropTypes from 'prop-types';
 
 const AUTO_HIDE_DURATION = 3000;  // In milliseconds
 
 let snackbarRef;
-function SnackbarUtilsConfigurator() {
-  snackbarRef = useSnackbar();
-  return <></>;
-}
-
 let notifierInitialized = false;
 export function initializeNotifier(notifierContainer) {
   notifierInitialized = true;
+  const RefLoad = ()=>{
+    snackbarRef = useSnackbar();
+    return <></>;
+  };
   ReactDOM.render(
     <Theme>
       <SnackbarProvider
         maxSnack={30}
         anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}>
-        <SnackbarUtilsConfigurator />
+        <RefLoad />
       </SnackbarProvider>
     </Theme>, notifierContainer
   );
 }
 
-export const FinalNotifyContent = React.forwardRef(({children}, ref) => {
+let modalRef;
+let modalInitialized = false;
+export function initializeModalProvider(modalContainer) {
+  modalInitialized = true;
+  const RefLoad = ()=>{
+    modalRef = useModal();
+    return <></>;
+  };
+  ReactDOM.render(
+    <Theme>
+      <ModalProvider>
+        <RefLoad />
+      </ModalProvider>
+    </Theme>, modalContainer
+  );
+}
+
+const FinalNotifyContent = React.forwardRef(({children}, ref) => {
   return <SnackbarContent style= {{justifyContent:'end'}} ref={ref}>{children}</SnackbarContent>;
 });
 FinalNotifyContent.displayName = 'FinalNotifyContent';
@@ -47,6 +71,38 @@ FinalNotifyContent.propTypes = {
   children: CustomPropTypes.children,
 };
 
+const useAlertStyles = makeStyles((theme)=>({
+  footer: {
+    display: 'flex',
+    justifyContent: 'flex-end',
+    padding: '0.5rem',
+    ...theme.mixins.panelBorder.top,
+  },
+  margin: {
+    marginLeft: '0.25rem',
+  }
+}));
+function AlertContent({text, confirm, onOkClick, onCancelClick}) {
+  const classes = useAlertStyles();
+  return (
+    <Box display="flex" flexDirection="column" height="100%">
+      <Box flexGrow="1" p={2}>{HTMLReactParse(text)}</Box>
+      <Box className={classes.footer}>
+        <DefaultButton startIcon={<CloseIcon />} onClick={onCancelClick} autoFocus={!confirm}>Close</DefaultButton>
+        {confirm &&
+          <PrimaryButton className={classes.margin} startIcon={<CheckRoundedIcon />} onClick={onOkClick} autoFocus={confirm}>OK</PrimaryButton>
+        }
+      </Box>
+    </Box>
+  );
+}
+AlertContent.propTypes = {
+  text: PropTypes.string,
+  confirm: PropTypes.bool,
+  onOkClick: PropTypes.func,
+  onCancelClick: PropTypes.func,
+};
+
 var Notifier = {
   success(msg, autoHideDuration = AUTO_HIDE_DURATION) {
     this._callNotify(msg, MESSAGE_TYPE.SUCCESS, autoHideDuration);
@@ -170,7 +226,39 @@ var Notifier = {
     Alertify.alert().show().set(
       'message', msg.replace(new RegExp(/\r?\n/, 'g'), '<br />')
     ).set('title', promptmsg).set('closable', true);
-  }
+  },
+  alert: (title, text, onCancelClick)=>{
+    if(!modalInitialized) {
+      initializeModalProvider(document.getElementById('modalContainer'));
+    }
+    modalRef.showModal(title, (closeModal)=>{
+      const onCancelClickClose = ()=>{
+        onCancelClick && onCancelClick();
+        closeModal();
+      };
+      return (
+        <AlertContent text={text} onCancelClick={onCancelClickClose} />
+      );
+    });
+  },
+  confirm: (title, text, onOkClick, onCancelClick)=>{
+    if(!modalInitialized) {
+      initializeModalProvider(document.getElementById('modalContainer'));
+    }
+    modalRef.showModal(title, (closeModal)=>{
+      const onCancelClickClose = ()=>{
+        onCancelClick && onCancelClick();
+        closeModal();
+      };
+      const onOkClickClose = ()=>{
+        onOkClick && onOkClick();
+        closeModal();
+      };
+      return (
+        <AlertContent text={text} confirm onOkClick={onOkClickClose} onCancelClick={onCancelClickClose} />
+      );
+    });
+  },
 };
 
 if(window.frameElement) {
diff --git a/web/pgadmin/templates/base.html b/web/pgadmin/templates/base.html
index 8fce32a8e..665cab9e4 100644
--- a/web/pgadmin/templates/base.html
+++ b/web/pgadmin/templates/base.html
@@ -75,6 +75,7 @@
 
 {% block body %}{% endblock %}
 <div id="notifierContainer"></div>
+<div id="modalContainer"></div>
 <script type="application/javascript">
             {% block init_script %}{% endblock %}
 </script>
diff --git a/web/yarn.lock b/web/yarn.lock
index d68f34ea4..a156a8490 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -2907,7 +2907,7 @@ closest@^0.0.1:
   dependencies:
     matches-selector "0.0.1"
 
-clsx@^1.0.2, clsx@^1.0.4, clsx@^1.1.0:
+clsx@^1.0.2, clsx@^1.0.4, clsx@^1.1.0, clsx@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
   integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
@@ -7782,6 +7782,14 @@ react-dom@^17.0.1:
     object-assign "^4.1.1"
     scheduler "^0.20.2"
 
+react-draggable@^4.4.4:
+  version "4.4.4"
+  resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.4.tgz#5b26d9996be63d32d285a426f41055de87e59b2f"
+  integrity sha512-6e0WdcNLwpBx/YIDpoyd2Xb04PB0elrDrulKUgdrIlwuYvxh5Ok9M+F8cljm8kPXXs43PmMzek9RrB1b7mLMqA==
+  dependencies:
+    clsx "^1.1.1"
+    prop-types "^15.6.0"
+
 react-input-autosize@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-3.0.0.tgz#6b5898c790d4478d69420b55441fcc31d5c50a85"
