diff --git a/web/roles/delete-role-modal.css b/web/roles/delete-role-modal.css
new file mode 100644
index 000000000..443d4cc4f
--- /dev/null
+++ b/web/roles/delete-role-modal.css
@@ -0,0 +1,20 @@
+.roleDeletionText {
+ color: var(--modal-fg);
+ font-size: var(--m-font-14);
+ padding: 16px 32px;
+}
+
+.buttonsContainer {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+ padding: 16px 32px;
+}
+
+.cancelButton {
+ width: 100px;
+}
+
+.deleteRoleButton {
+ margin-left: 8px;
+}
diff --git a/web/roles/delete-role-modal.react.js b/web/roles/delete-role-modal.react.js
new file mode 100644
index 000000000..5caa99bfc
--- /dev/null
+++ b/web/roles/delete-role-modal.react.js
@@ -0,0 +1,111 @@
+// @flow
+
+import * as React from 'react';
+
+import {
+ deleteCommunityRole,
+ deleteCommunityRoleActionTypes,
+} from 'lib/actions/thread-actions.js';
+import { useModalContext } from 'lib/components/modal-provider.react.js';
+import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
+import { useRoleMemberCountsForCommunity } from 'lib/shared/thread-utils.js';
+import type { LoadingStatus } from 'lib/types/loading-types.js';
+import type { ThreadInfo } from 'lib/types/thread-types.js';
+import {
+ useServerCall,
+ useDispatchActionPromise,
+} from 'lib/utils/action-utils.js';
+import { constructRoleDeletionMessagePrompt } from 'lib/utils/role-utils.js';
+
+import css from './delete-role-modal.css';
+import Button, { buttonThemes } from '../components/button.react.js';
+import LoadingIndicator from '../loading-indicator.react.js';
+import Modal from '../modals/modal.react.js';
+import { useSelector } from '../redux/redux-utils.js';
+
+const deleteRoleLoadingStatusSelector = createLoadingStatusSelector(
+ deleteCommunityRoleActionTypes,
+);
+
+type DeleteRoleModalProps = {
+ +threadInfo: ThreadInfo,
+ +defaultRoleID: string,
+ +roleID: string,
+};
+
+function DeleteRoleModal(props: DeleteRoleModalProps): React.Node {
+ const { threadInfo, defaultRoleID, roleID } = props;
+ const { popModal } = useModalContext();
+
+ const callDeleteCommunityRole = useServerCall(deleteCommunityRole);
+ const dispatchActionPromise = useDispatchActionPromise();
+
+ const deleteRoleLoadingStatus: LoadingStatus = useSelector(
+ deleteRoleLoadingStatusSelector,
+ );
+
+ const roleNamesToMemberCounts = useRoleMemberCountsForCommunity(threadInfo);
+ const roleName = threadInfo.roles[roleID].name;
+ const memberCount = roleNamesToMemberCounts[roleName];
+ const defaultRoleName = threadInfo.roles[defaultRoleID].name;
+
+ const message = constructRoleDeletionMessagePrompt(
+ defaultRoleName,
+ memberCount,
+ );
+
+ const onDeleteRole = React.useCallback(() => {
+ dispatchActionPromise(
+ deleteCommunityRoleActionTypes,
+ (async () => {
+ const response = await callDeleteCommunityRole({
+ community: threadInfo.id,
+ roleID: roleID,
+ });
+ popModal();
+ return response;
+ })(),
+ );
+ }, [
+ callDeleteCommunityRole,
+ dispatchActionPromise,
+ roleID,
+ threadInfo.id,
+ popModal,
+ ]);
+
+ const deleteButtonContent = React.useMemo(() => {
+ if (deleteRoleLoadingStatus === 'loading') {
+ return (
+