diff --git a/web/account/log-in-form.react.js b/web/account/log-in-form.react.js
--- a/web/account/log-in-form.react.js
+++ b/web/account/log-in-form.react.js
@@ -63,7 +63,7 @@
           password,
           ...extraInfo,
         });
-        modalContext.clearModal();
+        modalContext.popModal();
         return result;
       } catch (e) {
         if (e.message === 'invalid_parameters') {
diff --git a/web/app.react.js b/web/app.react.js
--- a/web/app.react.js
+++ b/web/app.react.js
@@ -79,7 +79,7 @@
   +activeThreadCurrentlyUnread: boolean,
   // Redux dispatch functions
   +dispatch: Dispatch,
-  +modal: ?React.Node,
+  +modals: $ReadOnlyArray<React.Node>,
 };
 class App extends React.PureComponent<Props> {
   componentDidMount() {
@@ -141,7 +141,7 @@
           <FocusHandler />
           <VisibilityHandler />
           {content}
-          {this.props.modal}
+          {this.props.modals}
         </MenuProvider>
       </DndProvider>
     );
@@ -237,6 +237,13 @@
 
     const dispatch = useDispatch();
     const modalContext = useModalContext();
+    const modals = React.useMemo(
+      () =>
+        modalContext.modals.map(([modal, key]) => (
+          <React.Fragment key={key}>{modal}</React.Fragment>
+        )),
+      [modalContext.modals],
+    );
 
     return (
       <App
@@ -246,7 +253,7 @@
         loggedIn={loggedIn}
         activeThreadCurrentlyUnread={activeThreadCurrentlyUnread}
         dispatch={dispatch}
-        modal={modalContext.modal}
+        modals={modals}
       />
     );
   },
diff --git a/web/calendar/day.react.js b/web/calendar/day.react.js
--- a/web/calendar/day.react.js
+++ b/web/calendar/day.react.js
@@ -45,7 +45,7 @@
   +nextLocalID: number,
   +timeZone: ?string,
   +dispatch: Dispatch,
-  +setModal: (modal: ?React.Node) => void,
+  +pushModal: (modal: React.Node) => void,
 };
 type State = {
   +pickerOpen: boolean,
@@ -216,7 +216,7 @@
 
   createNewEntry = (threadID: string) => {
     if (!this.props.loggedIn) {
-      this.props.setModal(<LogInFirstModal inOrderTo="edit this calendar" />);
+      this.props.pushModal(<LogInFirstModal inOrderTo="edit this calendar" />);
       return;
     }
     const viewerID = this.props.viewerID;
@@ -234,7 +234,7 @@
 
   onHistory = (event: SyntheticEvent<HTMLAnchorElement>) => {
     event.preventDefault();
-    this.props.setModal(
+    this.props.pushModal(
       <HistoryModal mode="day" dayString={this.props.dayString} />,
     );
   };
@@ -273,7 +273,7 @@
         nextLocalID={nextLocalID}
         timeZone={timeZone}
         dispatch={dispatch}
-        setModal={modalContext.setModal}
+        pushModal={modalContext.pushModal}
       />
     );
   },
diff --git a/web/calendar/entry.react.js b/web/calendar/entry.react.js
--- a/web/calendar/entry.react.js
+++ b/web/calendar/entry.react.js
@@ -68,8 +68,8 @@
   +createEntry: (info: CreateEntryInfo) => Promise<CreateEntryPayload>,
   +saveEntry: (info: SaveEntryInfo) => Promise<SaveEntryResult>,
   +deleteEntry: (info: DeleteEntryInfo) => Promise<DeleteEntryResult>,
-  +setModal: (modal: ?React.Node) => void,
-  +clearModal: () => void,
+  +pushModal: (modal: React.Node) => void,
+  +popModal: () => void,
 };
 type State = {
   +focused: boolean,
@@ -259,7 +259,7 @@
 
   onChange: (event: SyntheticEvent<HTMLTextAreaElement>) => void = event => {
     if (!this.props.loggedIn) {
-      this.props.setModal(<LogInFirstModal inOrderTo="edit this calendar" />);
+      this.props.pushModal(<LogInFirstModal inOrderTo="edit this calendar" />);
       return;
     }
     const target = event.target;
@@ -386,9 +386,9 @@
             type: concurrentModificationResetActionType,
             payload: { id: entryID, dbText: e.payload.db },
           });
-          this.props.clearModal();
+          this.props.popModal();
         };
-        this.props.setModal(
+        this.props.pushModal(
           <ConcurrentModificationModal onRefresh={onRefresh} />,
         );
       }
@@ -399,7 +399,7 @@
   onDelete: (event: SyntheticEvent<HTMLAnchorElement>) => void = event => {
     event.preventDefault();
     if (!this.props.loggedIn) {
-      this.props.setModal(<LogInFirstModal inOrderTo="edit this calendar" />);
+      this.props.pushModal(<LogInFirstModal inOrderTo="edit this calendar" />);
       return;
     }
     this.dispatchDelete(this.props.entryInfo.id, true);
@@ -440,7 +440,7 @@
 
   onHistory: (event: SyntheticEvent<HTMLAnchorElement>) => void = event => {
     event.preventDefault();
-    this.props.setModal(
+    this.props.pushModal(
       <HistoryModal
         mode="entry"
         dayString={dateString(
@@ -490,8 +490,8 @@
         deleteEntry={callDeleteEntry}
         dispatchActionPromise={dispatchActionPromise}
         dispatch={dispatch}
-        setModal={modalContext.setModal}
-        clearModal={modalContext.clearModal}
+        pushModal={modalContext.pushModal}
+        popModal={modalContext.popModal}
       />
     );
   },
diff --git a/web/calendar/filter-panel.react.js b/web/calendar/filter-panel.react.js
--- a/web/calendar/filter-panel.react.js
+++ b/web/calendar/filter-panel.react.js
@@ -42,7 +42,7 @@
   +filteredThreadIDs: ?$ReadOnlySet<string>,
   +includeDeleted: boolean,
   +dispatch: Dispatch,
-  +setModal: (modal: ?React.Node) => void,
+  +pushModal: (modal: React.Node) => void,
 };
 type State = {
   +query: string,
@@ -202,7 +202,7 @@
   }
 
   onClickSettings = (threadID: string) => {
-    this.props.setModal(<ThreadSettingsModal threadID={threadID} />);
+    this.props.pushModal(<ThreadSettingsModal threadID={threadID} />);
   };
 
   onChangeQuery = (event: SyntheticEvent<HTMLInputElement>) => {
@@ -377,7 +377,7 @@
         filterThreadSearchIndex={filterThreadSearchIndex}
         includeDeleted={includeDeleted}
         dispatch={dispatch}
-        setModal={modalContext.setModal}
+        pushModal={modalContext.pushModal}
       />
     );
   },
diff --git a/web/chat/chat-thread-list-see-more-sidebars.react.js b/web/chat/chat-thread-list-see-more-sidebars.react.js
--- a/web/chat/chat-thread-list-see-more-sidebars.react.js
+++ b/web/chat/chat-thread-list-see-more-sidebars.react.js
@@ -16,11 +16,11 @@
 };
 function ChatThreadListSeeMoreSidebars(props: Props): React.Node {
   const { unread, showingSidebarsInline, threadInfo } = props;
-  const { setModal } = useModalContext();
+  const { pushModal } = useModalContext();
 
   const onClick = React.useCallback(
-    () => setModal(<SidebarListModal threadInfo={threadInfo} />),
-    [setModal, threadInfo],
+    () => pushModal(<SidebarListModal threadInfo={threadInfo} />),
+    [pushModal, threadInfo],
   );
   const buttonText = showingSidebarsInline ? 'See more...' : 'See sidebars...';
   return (
diff --git a/web/chat/thread-menu.react.js b/web/chat/thread-menu.react.js
--- a/web/chat/thread-menu.react.js
+++ b/web/chat/thread-menu.react.js
@@ -41,13 +41,13 @@
 };
 
 function ThreadMenu(props: ThreadMenuProps): React.Node {
-  const { setModal, clearModal } = useModalContext();
+  const { pushModal, popModal } = useModalContext();
   const { threadInfo } = props;
   const { onPromoteSidebar } = usePromoteSidebar(threadInfo);
 
   const onClickSettings = React.useCallback(
-    () => setModal(<ThreadSettingsModal threadID={threadInfo.id} />),
-    [setModal, threadInfo.id],
+    () => pushModal(<ThreadSettingsModal threadID={threadInfo.id} />),
+    [pushModal, threadInfo.id],
   );
 
   const settingsItem = React.useMemo(() => {
@@ -63,10 +63,10 @@
 
   const onClickMembers = React.useCallback(
     () =>
-      setModal(
-        <ThreadMembersModal threadID={threadInfo.id} onClose={clearModal} />,
+      pushModal(
+        <ThreadMembersModal threadID={threadInfo.id} onClose={popModal} />,
       ),
-    [clearModal, setModal, threadInfo.id],
+    [popModal, pushModal, threadInfo.id],
   );
   const membersItem = React.useMemo(() => {
     if (threadInfo.type === threadTypes.PERSONAL) {
@@ -93,8 +93,8 @@
   }, [childThreads]);
 
   const onClickSidebars = React.useCallback(
-    () => setModal(<SidebarListModal threadInfo={threadInfo} />),
-    [setModal, threadInfo],
+    () => pushModal(<SidebarListModal threadInfo={threadInfo} />),
+    [pushModal, threadInfo],
   );
 
   const sidebarItem = React.useMemo(() => {
@@ -122,10 +122,10 @@
 
   const onClickViewSubchannels = React.useCallback(
     () =>
-      setModal(
-        <SubchannelsModal threadID={threadInfo.id} onClose={clearModal} />,
+      pushModal(
+        <SubchannelsModal threadID={threadInfo.id} onClose={popModal} />,
       ),
-    [clearModal, setModal, threadInfo.id],
+    [popModal, pushModal, threadInfo.id],
   );
 
   const viewSubchannelsItem = React.useMemo(() => {
@@ -163,19 +163,19 @@
       leaveThreadActionTypes,
       callLeaveThread(threadInfo.id),
     );
-    clearModal();
-  }, [callLeaveThread, clearModal, dispatchActionPromise, threadInfo.id]);
+    popModal();
+  }, [callLeaveThread, popModal, dispatchActionPromise, threadInfo.id]);
 
   const onClickLeaveThread = React.useCallback(
     () =>
-      setModal(
+      pushModal(
         <ConfirmLeaveThreadModal
           threadInfo={threadInfo}
-          onClose={clearModal}
+          onClose={popModal}
           onConfirm={onConfirmLeaveThread}
         />,
       ),
-    [clearModal, onConfirmLeaveThread, setModal, threadInfo],
+    [popModal, onConfirmLeaveThread, pushModal, threadInfo],
   );
 
   const leaveThreadItem = React.useMemo(() => {
diff --git a/web/input/input-state-container.react.js b/web/input/input-state-container.react.js
--- a/web/input/input-state-container.react.js
+++ b/web/input/input-state-container.react.js
@@ -108,7 +108,7 @@
     text: string,
   ) => Promise<SendMessageResult>,
   +newThread: (request: ClientNewThreadRequest) => Promise<NewThreadResult>,
-  +setModal: (modal: ?React.Node) => void,
+  +pushModal: (modal: React.Node) => void,
 };
 type State = {
   +pendingUploads: {
@@ -512,14 +512,14 @@
     files: $ReadOnlyArray<File>,
   ): Promise<boolean> {
     const selectionTime = Date.now();
-    const { setModal } = this.props;
+    const { pushModal } = this.props;
 
     const appendResults = await Promise.all(
       files.map(file => this.appendFile(file, selectionTime)),
     );
 
     if (appendResults.some(({ result }) => !result.success)) {
-      setModal(<InvalidUploadModal />);
+      pushModal(<InvalidUploadModal />);
 
       const time = Date.now() - selectionTime;
       const reports = [];
@@ -1264,7 +1264,7 @@
         newThread={callNewThread}
         dispatch={dispatch}
         dispatchActionPromise={dispatchActionPromise}
-        setModal={modalContext.setModal}
+        pushModal={modalContext.pushModal}
       />
     );
   },
diff --git a/web/media/multimedia-modal.react.js b/web/media/multimedia-modal.react.js
--- a/web/media/multimedia-modal.react.js
+++ b/web/media/multimedia-modal.react.js
@@ -13,7 +13,7 @@
 
 type Props = {
   ...BaseProps,
-  +clearModal: (modal: ?React.Node) => void,
+  +popModal: (modal: ?React.Node) => void,
 };
 
 class MultimediaModal extends React.PureComponent<Props> {
@@ -35,7 +35,7 @@
       >
         <img src={this.props.uri} />
         <XCircleIcon
-          onClick={this.props.clearModal}
+          onClick={this.props.popModal}
           className={css.closeMultimediaModal}
         />
       </div>
@@ -50,7 +50,7 @@
     event: SyntheticEvent<HTMLDivElement>,
   ) => void = event => {
     if (event.target === this.overlay) {
-      this.props.clearModal();
+      this.props.popModal();
     }
   };
 
@@ -58,7 +58,7 @@
     event: SyntheticKeyboardEvent<HTMLDivElement>,
   ) => void = event => {
     if (event.keyCode === 27) {
-      this.props.clearModal();
+      this.props.popModal();
     }
   };
 }
@@ -66,7 +66,7 @@
 function ConnectedMultiMediaModal(props: BaseProps): React.Node {
   const modalContext = useModalContext();
 
-  return <MultimediaModal {...props} clearModal={modalContext.clearModal} />;
+  return <MultimediaModal {...props} popModal={modalContext.popModal} />;
 }
 
 export default ConnectedMultiMediaModal;
diff --git a/web/media/multimedia.react.js b/web/media/multimedia.react.js
--- a/web/media/multimedia.react.js
+++ b/web/media/multimedia.react.js
@@ -24,7 +24,7 @@
 };
 type Props = {
   ...BaseProps,
-  +setModal: (modal: ?React.Node) => void,
+  +pushModal: (modal: React.Node) => void,
 };
 
 class Multimedia extends React.PureComponent<Props> {
@@ -44,7 +44,7 @@
   render(): React.Node {
     let progressIndicator, errorIndicator, removeButton;
 
-    const { pendingUpload, remove, setModal } = this.props;
+    const { pendingUpload, remove } = this.props;
     if (pendingUpload) {
       const { progressPercent, failed } = pendingUpload;
 
@@ -79,16 +79,15 @@
       css.multimediaImage,
       this.props.multimediaImageCSSClass,
     ];
-    let onClick;
-    if (setModal) {
-      imageContainerClasses.push(css.clickable);
-      onClick = this.onClick;
-    }
+    imageContainerClasses.push(css.clickable);
 
     const containerClasses = [css.multimedia, this.props.multimediaCSSClass];
     return (
       <span className={classNames(containerClasses)}>
-        <span className={classNames(imageContainerClasses)} onClick={onClick}>
+        <span
+          className={classNames(imageContainerClasses)}
+          onClick={this.onClick}
+        >
           <img src={this.props.uri} />
           {removeButton}
         </span>
@@ -111,16 +110,15 @@
   onClick: (event: SyntheticEvent<HTMLSpanElement>) => void = event => {
     event.stopPropagation();
 
-    const { setModal, uri } = this.props;
-    invariant(setModal, 'should be set');
-    setModal(<MultimediaModal uri={uri} />);
+    const { pushModal, uri } = this.props;
+    pushModal(<MultimediaModal uri={uri} />);
   };
 }
 
 function ConnectedMultimediaContainer(props: BaseProps): React.Node {
   const modalContext = useModalContext();
 
-  return <Multimedia {...props} setModal={modalContext.setModal} />;
+  return <Multimedia {...props} pushModal={modalContext.pushModal} />;
 }
 
 export default ConnectedMultimediaContainer;
diff --git a/web/modals/account/log-in-first-modal.react.js b/web/modals/account/log-in-first-modal.react.js
--- a/web/modals/account/log-in-first-modal.react.js
+++ b/web/modals/account/log-in-first-modal.react.js
@@ -13,14 +13,14 @@
 
 type Props = {
   ...BaseProps,
-  +setModal: (modal: ?React.Node) => void,
-  +clearModal: () => void,
+  +pushModal: (modal: React.Node) => void,
+  +popModal: () => void,
 };
 
 class LogInFirstModal extends React.PureComponent<Props> {
   render(): React.Node {
     return (
-      <Modal name="Log in" onClose={this.props.clearModal}>
+      <Modal name="Log in" onClose={this.props.popModal}>
         <div className={css['modal-body']}>
           <p>
             {`In order to ${this.props.inOrderTo}, you'll first need to `}
@@ -40,7 +40,7 @@
 
   onClickLogIn: (event: SyntheticEvent<HTMLAnchorElement>) => void = event => {
     event.preventDefault();
-    this.props.setModal(<LogInModal />);
+    this.props.pushModal(<LogInModal />);
   };
 }
 
@@ -50,8 +50,8 @@
   return (
     <LogInFirstModal
       {...props}
-      setModal={modalContext.setModal}
-      clearModal={modalContext.clearModal}
+      pushModal={modalContext.pushModal}
+      popModal={modalContext.popModal}
     />
   );
 }
diff --git a/web/modals/account/log-in-modal.react.js b/web/modals/account/log-in-modal.react.js
--- a/web/modals/account/log-in-modal.react.js
+++ b/web/modals/account/log-in-modal.react.js
@@ -9,7 +9,7 @@
 function LoginModal(): React.Node {
   const modalContext = useModalContext();
   return (
-    <Modal name="Log in" onClose={modalContext.clearModal}>
+    <Modal name="Log in" onClose={modalContext.popModal}>
       <LoginForm />
     </Modal>
   );
diff --git a/web/modals/account/user-settings-modal.react.js b/web/modals/account/user-settings-modal.react.js
--- a/web/modals/account/user-settings-modal.react.js
+++ b/web/modals/account/user-settings-modal.react.js
@@ -70,7 +70,7 @@
   ) => Promise<LogOutResult>,
   +changeUserPassword: (passwordUpdate: PasswordUpdate) => Promise<void>,
   +logOut: (preRequestUserState: PreRequestUserState) => Promise<LogOutResult>,
-  +clearModal: () => void,
+  +popModal: () => void,
 };
 type State = {
   +newPassword: string,
@@ -113,7 +113,7 @@
 
   logOut = async () => {
     await this.props.logOut(this.props.preRequestUserState);
-    this.props.clearModal();
+    this.props.popModal();
   };
 
   render() {
@@ -204,7 +204,7 @@
     }
 
     return (
-      <Modal name="Edit account" onClose={this.props.clearModal} size="large">
+      <Modal name="Edit account" onClose={this.props.popModal} size="large">
         <ul className={css['tab-panel']}>
           <Tab
             name="General"
@@ -326,7 +326,7 @@
         },
         currentPassword: this.state.currentPassword,
       });
-      this.props.clearModal();
+      this.props.popModal();
     } catch (e) {
       if (e.message === 'invalid_credentials') {
         this.setState(
@@ -375,7 +375,7 @@
         this.state.currentPassword,
         this.props.preRequestUserState,
       );
-      this.props.clearModal();
+      this.props.popModal();
       return response;
     } catch (e) {
       const errorMessage =
@@ -431,7 +431,7 @@
         changeUserPassword={callChangeUserPassword}
         dispatchActionPromise={dispatchActionPromise}
         logOut={boundLogOut}
-        clearModal={modalContext.clearModal}
+        popModal={modalContext.popModal}
       />
     );
   },
diff --git a/web/modals/chat/invalid-upload.react.js b/web/modals/chat/invalid-upload.react.js
--- a/web/modals/chat/invalid-upload.react.js
+++ b/web/modals/chat/invalid-upload.react.js
@@ -8,16 +8,16 @@
 import css from './invalid-upload.css';
 
 type Props = {
-  +clearModal: () => void,
+  +popModal: () => void,
 };
 class InvalidUploadModal extends React.PureComponent<Props> {
   render(): React.Node {
     return (
-      <Modal name="Invalid upload" onClose={this.props.clearModal}>
+      <Modal name="Invalid upload" onClose={this.props.popModal}>
         <div className={css.modal_body}>
           <p>We don&apos;t support that file type yet :(</p>
           <Button
-            onClick={this.props.clearModal}
+            onClick={this.props.popModal}
             type="submit"
             variant="primary"
             className={css.ok_button}
@@ -33,7 +33,7 @@
 function ConnectedInvalidUploadModal(): React.Node {
   const modalContext = useModalContext();
 
-  return <InvalidUploadModal clearModal={modalContext.clearModal} />;
+  return <InvalidUploadModal popModal={modalContext.popModal} />;
 }
 
 export default ConnectedInvalidUploadModal;
diff --git a/web/modals/chat/sidebar-list-modal.react.js b/web/modals/chat/sidebar-list-modal.react.js
--- a/web/modals/chat/sidebar-list-modal.react.js
+++ b/web/modals/chat/sidebar-list-modal.react.js
@@ -28,7 +28,7 @@
     text: '',
     results: new Set<string>(),
   });
-  const { clearModal } = useModalContext();
+  const { popModal } = useModalContext();
 
   const sidebarInfos = useSelector(
     state => sidebarInfoSelector(state)[threadInfo.id] ?? [],
@@ -53,12 +53,12 @@
             chatThreadListCSS.sidebar,
           )}
           key={item.threadInfo.id}
-          onClick={clearModal}
+          onClick={popModal}
         >
           <SidebarItem sidebarInfo={item} />
         </div>
       )),
-    [clearModal, listData],
+    [popModal, listData],
   );
 
   const viewerID = useSelector(
@@ -115,7 +115,7 @@
   }
 
   return (
-    <Modal name="Sidebars" onClose={clearModal} fixedHeight={false}>
+    <Modal name="Sidebars" onClose={popModal} fixedHeight={false}>
       <div
         className={classNames(
           globalCSS['modal-body'],
diff --git a/web/modals/concurrent-modification-modal.react.js b/web/modals/concurrent-modification-modal.react.js
--- a/web/modals/concurrent-modification-modal.react.js
+++ b/web/modals/concurrent-modification-modal.react.js
@@ -15,7 +15,7 @@
   const modalContext = useModalContext();
 
   return (
-    <Modal name="Concurrent modification" onClose={modalContext.clearModal}>
+    <Modal name="Concurrent modification" onClose={modalContext.popModal}>
       <div className={css.modal_body}>
         <p>
           It looks like somebody is attempting to modify that field at the same
diff --git a/web/modals/history/history-modal.react.js b/web/modals/history/history-modal.react.js
--- a/web/modals/history/history-modal.react.js
+++ b/web/modals/history/history-modal.react.js
@@ -275,7 +275,7 @@
         fetchEntries={callFetchEntries}
         fetchRevisionsForEntry={callFetchRevisionsForEntry}
         dispatchActionPromise={dispatchActionPromise}
-        onClose={modalContext.clearModal}
+        onClose={modalContext.popModal}
       />
     );
   },
diff --git a/web/modals/modal-provider.react.js b/web/modals/modal-provider.react.js
--- a/web/modals/modal-provider.react.js
+++ b/web/modals/modal-provider.react.js
@@ -3,35 +3,51 @@
 import invariant from 'invariant';
 import * as React from 'react';
 
+import { getUUID } from 'lib/utils/uuid';
+
 type Props = {
   +children: React.Node,
 };
 type ModalContextType = {
-  +modal: ?React.Node,
-  +setModal: (?React.Node) => void,
-  +clearModal: () => void,
+  +modals: $ReadOnlyArray<[React.Node, string]>,
+  +pushModal: React.Node => void,
+  +popModal: () => void,
+  +clearModals: () => void,
 };
 
 const ModalContext: React.Context<?ModalContextType> = React.createContext<?ModalContextType>(
   {
-    modal: null,
-    setModal: () => {},
-    clearModal: () => {},
+    modals: [],
+    pushModal: () => {},
+    popModal: () => {},
+    clearModals: () => {},
   },
 );
 
 function ModalProvider(props: Props): React.Node {
   const { children } = props;
-  const [modal, setModal] = React.useState(null);
-  const clearModal = React.useCallback(() => setModal(null), []);
+  const [modals, setModals] = React.useState<
+    $ReadOnlyArray<[React.Node, string]>,
+  >([]);
+  const popModal = React.useCallback(
+    () => setModals(oldModals => oldModals.slice(0, oldModals.length - 1)),
+    [],
+  );
+  const pushModal = React.useCallback(newModal => {
+    const key = getUUID();
+    setModals(oldModals => [...oldModals, [newModal, key]]);
+  }, []);
+
+  const clearModals = React.useCallback(() => setModals([]), []);
 
   const value = React.useMemo(
     () => ({
-      modal,
-      setModal,
-      clearModal,
+      modals,
+      pushModal,
+      popModal,
+      clearModals,
     }),
-    [modal, clearModal],
+    [modals, pushModal, popModal, clearModals],
   );
 
   return (
diff --git a/web/modals/threads/subchannels/subchannel.react.js b/web/modals/threads/subchannels/subchannel.react.js
--- a/web/modals/threads/subchannels/subchannel.react.js
+++ b/web/modals/threads/subchannels/subchannel.react.js
@@ -26,16 +26,16 @@
   } = chatThreadItem;
 
   const timeZone = useSelector(state => state.timeZone);
-  const { clearModal } = useModalContext();
+  const { popModal } = useModalContext();
 
   const navigateToThread = useOnClickThread(threadInfo);
 
   const onClickThread = React.useCallback(
     event => {
-      clearModal();
+      popModal();
       navigateToThread(event);
     },
-    [clearModal, navigateToThread],
+    [popModal, navigateToThread],
   );
 
   const lastActivity = React.useMemo(
diff --git a/web/modals/threads/thread-settings-modal.react.js b/web/modals/threads/thread-settings-modal.react.js
--- a/web/modals/threads/thread-settings-modal.react.js
+++ b/web/modals/threads/thread-settings-modal.react.js
@@ -384,7 +384,7 @@
       invariant(threadInfo, 'threadInfo should exist in deleteThreadAction');
       try {
         const response = await callDeleteThread(threadInfo.id, accountPassword);
-        modalContext.clearModal();
+        modalContext.popModal();
         return response;
       } catch (e) {
         setErrorMessage(
@@ -417,7 +417,7 @@
           threadID: threadInfo.id,
           changes: queuedChanges,
         });
-        modalContext.clearModal();
+        modalContext.popModal();
         return response;
       } catch (e) {
         setErrorMessage('unknown_error');
@@ -456,7 +456,7 @@
 
     if (!threadInfo) {
       return (
-        <Modal onClose={modalContext.clearModal} name="Invalid thread">
+        <Modal onClose={modalContext.popModal} name="Invalid thread">
           <div className={css.modal_body}>
             <p>You no longer have permission to view this thread</p>
           </div>
@@ -474,7 +474,7 @@
         deleteThread={callDeleteThread}
         changeThreadSettings={callChangeThreadSettings}
         dispatchActionPromise={dispatchActionPromise}
-        onClose={modalContext.clearModal}
+        onClose={modalContext.popModal}
         errorMessage={errorMessage}
         setErrorMessage={setErrorMessage}
         accountPassword={accountPassword}
diff --git a/web/settings/account-settings.react.js b/web/settings/account-settings.react.js
--- a/web/settings/account-settings.react.js
+++ b/web/settings/account-settings.react.js
@@ -19,10 +19,10 @@
     sendLogoutRequest(preRequestUserState);
   }, [sendLogoutRequest, preRequestUserState]);
 
-  const { setModal } = useModalContext();
+  const { pushModal } = useModalContext();
   const showPasswordChangeModal = React.useCallback(
-    () => setModal(<PasswordChangeModal />),
-    [setModal],
+    () => pushModal(<PasswordChangeModal />),
+    [pushModal],
   );
 
   const currentUserInfo = useSelector(state => state.currentUserInfo);
diff --git a/web/settings/password-change-modal.js b/web/settings/password-change-modal.js
--- a/web/settings/password-change-modal.js
+++ b/web/settings/password-change-modal.js
@@ -30,7 +30,7 @@
   +inputDisabled: boolean,
   +dispatchActionPromise: DispatchActionPromise,
   +changeUserPassword: (passwordUpdate: PasswordUpdate) => Promise<void>,
-  +clearModal: () => void,
+  +popModal: () => void,
 };
 type State = {
   +newPassword: string,
@@ -74,11 +74,7 @@
 
     const { inputDisabled } = this.props;
     return (
-      <Modal
-        name="Change Password"
-        onClose={this.props.clearModal}
-        size="large"
-      >
+      <Modal name="Change Password" onClose={this.props.popModal} size="large">
         <div className={css['modal-body']}>
           <form method="POST">
             <div className={css['form-content']}>
@@ -201,7 +197,7 @@
         },
         currentPassword: this.state.currentPassword,
       });
-      this.props.clearModal();
+      this.props.popModal();
     } catch (e) {
       if (e.message === 'invalid_credentials') {
         this.setState(
@@ -256,7 +252,7 @@
         inputDisabled={inputDisabled}
         changeUserPassword={callChangeUserPassword}
         dispatchActionPromise={dispatchActionPromise}
-        clearModal={modalContext.clearModal}
+        popModal={modalContext.popModal}
       />
     );
   },
diff --git a/web/sidebar/community-picker.react.js b/web/sidebar/community-picker.react.js
--- a/web/sidebar/community-picker.react.js
+++ b/web/sidebar/community-picker.react.js
@@ -9,11 +9,11 @@
 import css from './community-picker.css';
 
 function CommunityPicker(): React.Node {
-  const { setModal } = useModalContext();
+  const { pushModal } = useModalContext();
 
   const setModalToUserSettings = React.useCallback(() => {
-    setModal(<UserSettingsModal />);
-  }, [setModal]);
+    pushModal(<UserSettingsModal />);
+  }, [pushModal]);
 
   return (
     <div className={css.container}>