From bcf60cdcc509c13cd19714ccc8f0d8022b223b62 Mon Sep 17 00:00:00 2001
From: Julien Scholz <8947616+pikaju@users.noreply.github.com>
Date: Tue, 14 Feb 2023 21:10:59 +0100
Subject: [PATCH 1/6] Add keepMounted option
---
react-responsive-modal/src/index.tsx | 12 +++++++++---
react-responsive-modal/styles.css | 15 +++++++++++++++
website/src/docs/index.mdx | 1 +
3 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/react-responsive-modal/src/index.tsx b/react-responsive-modal/src/index.tsx
index 2427009d..9f8ed427 100644
--- a/react-responsive-modal/src/index.tsx
+++ b/react-responsive-modal/src/index.tsx
@@ -158,6 +158,11 @@ export interface ModalProps {
* Callback fired when the Modal has exited and the animation is finished.
*/
onAnimationEnd?: () => void;
+ /**
+ * Keeps the Modal mounted even when it is hidden. This is useful for keeping the DOM state
+ * inside the Modal as well as for SEO purposes.
+ */
+ keepMounted: boolean;
children?: React.ReactNode;
}
@@ -187,6 +192,7 @@ export const Modal = React.forwardRef(
onEscKeyDown,
onOverlayClick,
onAnimationEnd,
+ keepMounted = false,
children,
reserveScrollBarGap,
}: ModalProps,
@@ -260,7 +266,7 @@ export const Modal = React.forwardRef(
useEffect(() => {
// If the open prop is changing, we need to open the modal
// This is also called on the first render if the open prop is true when the modal is created
- if (open && !showPortal) {
+ if ((open || keepMounted) && !showPortal) {
setShowPortal(true);
handleOpen();
}
@@ -292,7 +298,7 @@ export const Modal = React.forwardRef(
};
const handleAnimationEnd = () => {
- if (!open) {
+ if (!open && !keepMounted) {
setShowPortal(false);
}
@@ -324,6 +330,7 @@ export const Modal = React.forwardRef(
animation: `${overlayAnimation} ${animationDuration}ms`,
...styles?.overlay,
}}
+ onClick={handleClickOverlay}
/>
void` | | Callback fired when the escape key is pressed. |
| **onOverlayClick\*** | `(event: React.MouseEvent) => void` | | Callback fired when the overlay is clicked. |
| **onAnimationEnd\*** | `() => void` | | Callback fired when the Modal has exited and the animation is finished. |
+| **keepMounted** | `boolean` | false | Keeps the Modal mounted to the DOM tree even when it is hidden. This is useful for keeping DOM state inside the Modal as well as for SEO purposes. |
## License
From c9a1da9d23435c13c29bf1725a31c284b303b4c9 Mon Sep 17 00:00:00 2001
From: Julien Scholz <8947616+pikaju@users.noreply.github.com>
Date: Tue, 14 Feb 2023 21:51:36 +0100
Subject: [PATCH 2/6] Fix keepMounted being required
---
react-responsive-modal/src/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/react-responsive-modal/src/index.tsx b/react-responsive-modal/src/index.tsx
index 9f8ed427..48e2d74f 100644
--- a/react-responsive-modal/src/index.tsx
+++ b/react-responsive-modal/src/index.tsx
@@ -162,7 +162,7 @@ export interface ModalProps {
* Keeps the Modal mounted even when it is hidden. This is useful for keeping the DOM state
* inside the Modal as well as for SEO purposes.
*/
- keepMounted: boolean;
+ keepMounted?: boolean;
children?: React.ReactNode;
}
From 53d933b38c40e590ded54f9ab8be3e98df2b9c65 Mon Sep 17 00:00:00 2001
From: Julien Scholz <8947616+pikaju@users.noreply.github.com>
Date: Tue, 14 Feb 2023 22:44:37 +0100
Subject: [PATCH 3/6] Fix bugs
---
react-responsive-modal/src/index.tsx | 18 +++++++++++++++---
react-responsive-modal/styles.css | 7 ++-----
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/react-responsive-modal/src/index.tsx b/react-responsive-modal/src/index.tsx
index 48e2d74f..9ff10152 100644
--- a/react-responsive-modal/src/index.tsx
+++ b/react-responsive-modal/src/index.tsx
@@ -212,6 +212,9 @@ export const Modal = React.forwardRef(
// it will match the server rendered content
const [showPortal, setShowPortal] = useState(false);
+ // Used to hide the modal when keepMounted is true
+ const [display, setDisplay] = useState(false);
+
// Hook used to manage multiple modals opened at the same time
useModalManager(refModal, open);
@@ -270,6 +273,9 @@ export const Modal = React.forwardRef(
setShowPortal(true);
handleOpen();
}
+ if (open && !display) {
+ setDisplay(true);
+ }
}, [open]);
const handleClickOverlay = (
@@ -298,8 +304,11 @@ export const Modal = React.forwardRef(
};
const handleAnimationEnd = () => {
- if (!open && !keepMounted) {
- setShowPortal(false);
+ if (!open) {
+ setDisplay(false);
+ if (!keepMounted) {
+ setShowPortal(false);
+ }
}
onAnimationEnd?.();
@@ -319,7 +328,10 @@ export const Modal = React.forwardRef(
? ReactDom.createPortal(
Date: Thu, 16 Mar 2023 17:36:44 +0100
Subject: [PATCH 5/6] Add example for keepMounted option
---
website/src/components/ExampleRendered.tsx | 2 ++
website/src/docs/index.mdx | 21 ++++++++++++++
website/src/examples/KeepMounted.tsx | 32 ++++++++++++++++++++++
website/src/pages/index.tsx | 8 ++++++
4 files changed, 63 insertions(+)
create mode 100644 website/src/examples/KeepMounted.tsx
diff --git a/website/src/components/ExampleRendered.tsx b/website/src/components/ExampleRendered.tsx
index 1f6086a3..3510ef69 100644
--- a/website/src/components/ExampleRendered.tsx
+++ b/website/src/components/ExampleRendered.tsx
@@ -3,6 +3,7 @@ import ExampleMultiple from '../examples/Multiple';
import LongContent from '../examples/LongContent';
import FocusTrapped from '../examples/FocusTrapped';
import FocusTrappedInitialFocus from '../examples/FocusTrappedInitialFocus';
+import KeepMounted from '../examples/KeepMounted';
import CustomCssStyle from '../examples/CustomCssStyle';
import CustomAnimation from '../examples/CustomAnimation';
import CustomCloseIcon from '../examples/CustomCloseIcon';
@@ -14,6 +15,7 @@ const examples: Record JSX.Element> = {
longContent: LongContent,
focusTrapped: FocusTrapped,
focusTrappedInitialFocus: FocusTrappedInitialFocus,
+ keepMounted: KeepMounted,
customCssStyle: CustomCssStyle,
customAnimation: CustomAnimation,
customCloseIcon: CustomCloseIcon,
diff --git a/website/src/docs/index.mdx b/website/src/docs/index.mdx
index 11165223..bc960168 100644
--- a/website/src/docs/index.mdx
+++ b/website/src/docs/index.mdx
@@ -8,6 +8,7 @@ A simple responsive and accessible react modal.
- Multiple modals.
- Accessible modals.
- Easily customizable via props.
+- Optionally keep hidden modals mounted to the DOM
- Typescript support
- [Small bundle size](https://bundlephobia.com/result?p=react-responsive-modal)
@@ -103,6 +104,26 @@ You can also set to trap focus within the modal, but decide where to put focus w
```
+### Keeping a hidden modal mounted
+
+By setting the `keepMounted` property to `true`, you can specify that the modal should always be mounted to the DOM, even when hidden it is hidden.
+Instead of removing the DOM nodes, the modal is hidden using `display: none`.
+
+```js
+
+ ...
+
+```
+
+This is useful when you want the state of the DOM nodes (e.g. the text inside an `` element) to stay alive, as well as for search engine optimization (Google can see the content of the hidden modal).
+
+Press the button below and watch the element tree in your browser. The modal is a `
` at the very bottom of the ``, and will not disappear even when the modal is closed!
+
+
+
### Custom styling with css
Customising the Modal style via css is really easy. For example if you add the following css to your app you will get the following result:
diff --git a/website/src/examples/KeepMounted.tsx b/website/src/examples/KeepMounted.tsx
new file mode 100644
index 00000000..2555eef5
--- /dev/null
+++ b/website/src/examples/KeepMounted.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import { Modal } from 'react-responsive-modal';
+
+const App = () => {
+ const [open, setOpen] = React.useState(false);
+
+ return (
+ <>
+
+
+ setOpen(false)} keepMounted>
+
+ This modal will stay mounted even when closed.
+
+
+
+