diff --git a/web/chat/edit-message-provider.js b/web/chat/edit-message-provider.js
--- a/web/chat/edit-message-provider.js
+++ b/web/chat/edit-message-provider.js
@@ -1,5 +1,6 @@
 // @flow
 
+import FocusTrap from 'focus-trap-react';
 import invariant from 'invariant';
 import * as React from 'react';
 
@@ -141,7 +142,11 @@
     if (!modal) {
       return null;
     }
-    return <ModalOverlay onClose={clearEditModal}>{modal}</ModalOverlay>;
+    return (
+      <ModalOverlay onClose={clearEditModal}>
+        <FocusTrap>{modal}</FocusTrap>
+      </ModalOverlay>
+    );
   }, [clearEditModal, modal]);
 
   return (
diff --git a/web/flow-typed/npm/focus-trap-react_vx.x.x.js b/web/flow-typed/npm/focus-trap-react_vx.x.x.js
new file mode 100644
--- /dev/null
+++ b/web/flow-typed/npm/focus-trap-react_vx.x.x.js
@@ -0,0 +1,31 @@
+// flow-typed signature: 29231f6b72f5876f5692b592dce3c754
+// flow-typed version: <<STUB>>/focus-trap-react_v10.1.4/flow_v0.182.0
+
+/**
+ * This is an autogenerated libdef stub for:
+ *
+ *   'focus-trap-react'
+ *
+ * Fill this stub out by replacing all the `any` types.
+ *
+ * Once filled out, we encourage you to share your work with the
+ * community by sending a pull request to:
+ * https://github.com/flowtype/flow-typed
+ */
+
+declare module 'focus-trap-react' {
+  import type { Element, Node } from 'react';
+
+  declare type FocusTrapOptions = {
+  }
+
+  declare type FocusTrapProps = {
+    +children?: Element<any>,
+    +active?: boolean,
+    +paused?: boolean,
+    +focusTrapOptions?: FocusTrapOptions,
+    +containerElements?: $ReadOnlyArray<HTMLElement>,
+  };
+
+  declare module.exports: FocusTrapProps => Node;
+}
diff --git a/web/modals/modal.react.js b/web/modals/modal.react.js
--- a/web/modals/modal.react.js
+++ b/web/modals/modal.react.js
@@ -1,6 +1,7 @@
 // @flow
 
 import classNames from 'classnames';
+import FocusTrap from 'focus-trap-react';
 import * as React from 'react';
 
 import ModalOverlay from 'lib/components/modal-overlay.react.js';
@@ -74,19 +75,21 @@
   }
   return (
     <ModalOverlay onClose={onClose}>
-      <div className={modalContainerClasses}>
-        <div className={modalHeader}>
-          <div className={css.modalHeaderTitle}>
-            <h2 className={css.title}>
-              {headerIcon}
-              {name}
-            </h2>
-            {cornerCloseButton}
+      <FocusTrap>
+        <div className={modalContainerClasses}>
+          <div className={modalHeader}>
+            <div className={css.modalHeaderTitle}>
+              <h2 className={css.title}>
+                {headerIcon}
+                {name}
+              </h2>
+              {cornerCloseButton}
+            </div>
+            {subtitleNode}
           </div>
-          {subtitleNode}
+          {children}
         </div>
-        {children}
-      </div>
+      </FocusTrap>
     </ModalOverlay>
   );
 }
diff --git a/web/package.json b/web/package.json
--- a/web/package.json
+++ b/web/package.json
@@ -53,6 +53,7 @@
     "emoji-mart": "^5.5.2",
     "ethers": "^5.7.2",
     "exif-js": "^2.3.0",
+    "focus-trap-react": "^10.1.4",
     "google-protobuf": "^3.21.2",
     "grpc-web": "^1.4.2",
     "history": "^4.6.3",
diff --git a/yarn.lock b/yarn.lock
--- a/yarn.lock
+++ b/yarn.lock
@@ -11776,6 +11776,21 @@
   dependencies:
     imul "^1.0.0"
 
+focus-trap-react@^10.1.4:
+  version "10.1.4"
+  resolved "https://registry.yarnpkg.com/focus-trap-react/-/focus-trap-react-10.1.4.tgz#bab7ea87aecfa2f7eb6f2fcc4be1e7311893ca17"
+  integrity sha512-vLUQRXI6SUJD8YLYTBa1DlCYRmTKFDxRvc4TEe2nq8S1aj+YKsucuNxqZUOf0+RZ01Yoiwtk/6rD9xqSvawIvQ==
+  dependencies:
+    focus-trap "^7.4.3"
+    tabbable "^6.1.2"
+
+focus-trap@^7.4.3:
+  version "7.4.3"
+  resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-7.4.3.tgz#a3dae73d44df359eb92bbf37b18e173e813b16c5"
+  integrity sha512-BgSSbK4GPnS2VbtZ50VtOv1Sti6DIkj3+LkVjiWMNjLeAp1SH1UlLx3ULu/DCu4vq5R4/uvTm+zrvsMsuYmGLg==
+  dependencies:
+    tabbable "^6.1.2"
+
 follow-redirects@^1.0.0:
   version "1.14.8"
   resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
@@ -22197,6 +22212,11 @@
   resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
   integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
 
+tabbable@^6.1.2:
+  version "6.1.2"
+  resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.1.2.tgz#b0d3ca81d582d48a80f71b267d1434b1469a3703"
+  integrity sha512-qCN98uP7i9z0fIS4amQ5zbGBOq+OSigYeGvPy7NDk8Y9yncqDZ9pRPgfsc2PJIVM9RrJj7GIfuRgmjoUU9zTHQ==
+
 table@^5.4.6:
   version "5.4.6"
   resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"