diff --git a/src/lib/components/Modal/Modal.spec.tsx b/src/lib/components/Modal/Modal.spec.tsx
index d2209c44e..7250b3059 100644
--- a/src/lib/components/Modal/Modal.spec.tsx
+++ b/src/lib/components/Modal/Modal.spec.tsx
@@ -24,6 +24,16 @@ describe('Components / Modal', () => {
waitFor(() => expect(input).toHaveFocus());
});
+ it('should be removed from DOM and garbage collected', async () => {
+ const root = document.createElement('div');
+
+ const { unmount } = render();
+
+ unmount();
+
+ await waitFor(() => expect(root.childNodes.length).toBe(0));
+ });
+
describe('A11y', () => {
it('should have `role="dialog"`', async () => {
const user = userEvent.setup();
diff --git a/src/lib/components/Modal/Modal.tsx b/src/lib/components/Modal/Modal.tsx
index f3d57ae7d..e4c50edf1 100644
--- a/src/lib/components/Modal/Modal.tsx
+++ b/src/lib/components/Modal/Modal.tsx
@@ -1,5 +1,5 @@
import classNames from 'classnames';
-import { ComponentProps, FC, PropsWithChildren, useRef } from 'react';
+import { ComponentProps, FC, PropsWithChildren, useEffect, useRef } from 'react';
import { createPortal } from 'react-dom';
import type { FlowbiteBoolean, FlowbitePositions, FlowbiteSizes } from '../Flowbite/FlowbiteTheme';
import { useTheme } from '../Flowbite/ThemeContext';
@@ -80,6 +80,19 @@ const ModalComponent: FC = ({
root.appendChild(containerRef.current);
}
+ useEffect(() => {
+ return () => {
+ const container = containerRef.current;
+
+ // If a container exists on unmount, it is removed from the DOM and
+ // garbage collected.
+ if (container) {
+ container.parentNode?.removeChild(container);
+ containerRef.current = null;
+ }
+ };
+ }, []);
+
return createPortal(