diff --git a/packages/component-modal/src/components/ConfirmationModal.js b/packages/component-modal/src/components/ConfirmationModal.js
index 1271f62d4d9bea5496033628b5297350a848ce75..c3436753c864b33c18c7756756e2ad29b894d4bb 100644
--- a/packages/component-modal/src/components/ConfirmationModal.js
+++ b/packages/component-modal/src/components/ConfirmationModal.js
@@ -1,6 +1,6 @@
 import React from 'react'
-import { Icon, Button, th } from '@pubsweet/ui'
 import { compose, withHandlers } from 'recompose'
+import { Icon, Button, th, Spinner } from '@pubsweet/ui'
 import styled, { css, withTheme } from 'styled-components'
 
 const ConfirmationModal = ({
@@ -13,6 +13,7 @@ const ConfirmationModal = ({
   cancelText = 'Cancel',
   theme,
   modalError,
+  isFetching,
 }) => (
   <Root>
     <CloseIcon data-test="icon-modal-hide" onClick={onClose}>
@@ -28,11 +29,16 @@ const ConfirmationModal = ({
       <Button data-test="button-modal-hide" onClick={onClose}>
         {cancelText}
       </Button>
-      {onConfirm && (
-        <Button data-test="button-modal-confirm" onClick={onConfirm} primary>
-          {confirmText}
-        </Button>
-      )}
+      {onConfirm &&
+        (isFetching ? (
+          <SpinnerContainer>
+            <Spinner size={4} />
+          </SpinnerContainer>
+        ) : (
+          <Button data-test="button-modal-confirm" onClick={onConfirm} primary>
+            {confirmText}
+          </Button>
+        ))}
     </ButtonsContainer>
   </Root>
 )
@@ -57,6 +63,14 @@ const defaultText = css`
   font-size: ${th('fontSizeBaseSmall')};
 `
 
+const SpinnerContainer = styled.div`
+  align-items: center;
+  display: flex;
+  justify-content: center;
+  height: calc(${th('gridUnit')} * 2);
+  min-width: calc(${th('gridUnit')} * 4);
+`
+
 const Root = styled.div`
   background-color: ${th('backgroundColor')};
   border: ${th('borderDefault')};
diff --git a/packages/components-faraday/src/components/Reviewers/InviteReviewers.js b/packages/components-faraday/src/components/Reviewers/InviteReviewers.js
index 6100c920a7ee86bc4ea13ff5c6ae3d2f7c9ae1c3..d0d31f9b947dee0c29544e6d1b8de26cfa5bd7bd 100644
--- a/packages/components-faraday/src/components/Reviewers/InviteReviewers.js
+++ b/packages/components-faraday/src/components/Reviewers/InviteReviewers.js
@@ -84,14 +84,18 @@ const InviteReviewersModal = compose(
   ),
 )
 
-const ModalSwitcher = ({ type, ...rest }) => {
+const ModalSwitcher = compose(
+  connect(state => ({
+    fetchingInvite: selectFechingInvite(state),
+  })),
+)(({ type, fetchingInvite, ...rest }) => {
   switch (type) {
     case 'invite-reviewers':
       return <InviteReviewersModal {...rest} />
     default:
-      return <ConfirmationModal {...rest} />
+      return <ConfirmationModal {...rest} isFetching={fetchingInvite} />
   }
-}
+})
 
 export default compose(
   withModal2(props => ({
diff --git a/packages/components-faraday/src/redux/reviewers.js b/packages/components-faraday/src/redux/reviewers.js
index 26733696179b0d243fb45af5de48b32ff5628b1c..549650f21ea5bc99ed82b4e2c440ff82afa079ae 100644
--- a/packages/components-faraday/src/redux/reviewers.js
+++ b/packages/components-faraday/src/redux/reviewers.js
@@ -68,8 +68,12 @@ export const inviteReviewer = (reviewerData, collectionId) => dispatch => {
   }).then(() => dispatch(inviteSuccess()), err => dispatch(inviteError(err)))
 }
 
-export const revokeReviewer = (invitationId, collectionId) => dispatch =>
-  remove(`/collections/${collectionId}/invitations/${invitationId}`)
+export const revokeReviewer = (invitationId, collectionId) => dispatch => {
+  dispatch(inviteRequest())
+  return remove(
+    `/collections/${collectionId}/invitations/${invitationId}`,
+  ).then(() => dispatch(inviteSuccess()), err => dispatch(inviteError(err)))
+}
 
 export default (state = initialState, action = {}) => {
   switch (action.type) {