diff --git a/packages/react/src/components/Dialog/Dialog-story.js b/packages/react/src/components/Dialog/Dialog-story.js
index c4066e5af415..72c526b19b02 100644
--- a/packages/react/src/components/Dialog/Dialog-story.js
+++ b/packages/react/src/components/Dialog/Dialog-story.js
@@ -6,8 +6,10 @@
*/
import * as React from 'react';
+import ReactDOM from 'react-dom';
import { FocusScope } from './FocusScope';
import { Dialog } from '../Dialog';
+import { useId } from '../../internal/useId';
export default {
title: 'Experimental/unstable_Dialog',
@@ -67,11 +69,14 @@ export const Default = () => {
export const DialogExample = () => {
function Example() {
const [open, setOpen] = React.useState(false);
+ const id = useId();
return (
- <>
+
+
+ {/* trigger */}
-
+ {/* full screen background */}
+
{
+ setOpen(false);
+ }}
+ />
+
+ {/* dialog */}
+
+
+ ) : null}
+
- >
+
);
}
return ;
};
+
+function FullPage(props) {
+ return (
+
+ );
+}
+
+function Portal({ children }) {
+ const [mountNode, setMountNode] = React.useState(null);
+
+ React.useEffect(() => {
+ // TODO: should this be configurable????
+ setMountNode(document.body);
+ }, []);
+
+ if (mountNode) {
+ return ReactDOM.createPortal(children, mountNode);
+ }
+
+ return null;
+}
diff --git a/packages/react/src/components/Dialog/FocusScope.js b/packages/react/src/components/Dialog/FocusScope.js
index 152e6a39fef5..ed2bf9aeb91a 100644
--- a/packages/react/src/components/Dialog/FocusScope.js
+++ b/packages/react/src/components/Dialog/FocusScope.js
@@ -87,7 +87,9 @@ function useRestoreFocus(container) {
element.removeEventListener('focusout', onFocusOut);
if (containsFocus.current === true) {
- focus(initialActiveElement);
+ setTimeout(() => {
+ focus(initialActiveElement);
+ }, 0);
}
};
}, []);
@@ -141,6 +143,7 @@ const FocusScope = React.forwardRef(function FocusScope(props, forwardRef) {
return (
<>
{
- if (open) {
- //
+ const changes = [];
+ const queue = Array.from(document.body.childNodes);
+
+ while (queue.length !== 0) {
+ const node = queue.shift();
+
+ // If a node is the modal (dialogRef), do nothing
+ if (node === dialogRef.current) {
+ continue;
+ }
+
+ // If a tree contains our `dialogRef`, traverse its children
+ if (node.contains(dialogRef.current)) {
+ queue.push(...Array.from(node.childNodes));
+ continue;
+ }
+
+ // If a node is a bumper, do nothing
+ if (
+ node.hasAttribute('data-dialog-bumper') &&
+ (dialogRef.current.previousSibling === node ||
+ dialogRef.current.nextSibling === node)
+ ) {
+ continue;
+ }
+
+ if (node.hasAttribute('aria-hidden') || node.hasAttribute('inert')) {
+ continue;
+ }
+
+ // what is aria-hidden === 'false'
+
+ // Otherwise, set it to inert and set aria-hidden to true
+ node.setAttribute('aria-hidden', 'true');
+ node.setAttribute('inert', '');
+
+ changes.push(node);
}
- }, [open]);
-
- if (open) {
- return (
-
-
-
- {children}
-
-
- );
- }
- return null;
+ return () => {
+ changes.forEach((node) => {
+ node.removeAttribute('inert');
+ // This mutation needs to be asynchronous to allow the polyfill time to
+ // observe the change and allow mutations to occur
+ // https://github.com/WICG/inert#performance-and-gotchas
+ setTimeout(() => {
+ node.removeAttribute('aria-hidden');
+ }, 0);
+ });
+ };
+ }, []);
+
+ return (
+
+ {children}
+
+ );
});
Dialog.propTypes = {};
@@ -88,25 +109,4 @@ if (__DEV__) {
Dialog.displayName = 'Dialog';
}
-function Portal({ children, ...rest }) {
- return {children}
;
-}
-
-function FullPage(props) {
- return (
-
- );
-}
-
export { Dialog };