@@ -28,18 +28,30 @@ import { warn } from '../../util/logger.js';
2828import { BaseModalProps , ModalComponent } from './types.js' ;
2929import './Modal.css' ;
3030
31+ const PORTAL_CLASS_NAME = 'cui-modal-portal' ;
32+ const HTML_OPEN_CLASS_NAME = 'cui-modal-open' ;
33+ // These are the default app element ids in Next.js, Docusaurus, CRA and Storybook.
34+ const APP_ELEMENT_IDS = [ 'root' , '__next' , '__docusaurus' , 'storybook-root' ] ;
35+
36+ function getAppElement ( ) : HTMLElement | null {
37+ // eslint-disable-next-line no-restricted-syntax
38+ for ( const id of APP_ELEMENT_IDS ) {
39+ const element = document . getElementById ( id ) ;
40+
41+ if ( element ) {
42+ return element ;
43+ }
44+ }
45+ return null ;
46+ }
47+
3148// It is important for users of screen readers that other page content be hidden
3249// (via the `aria-hidden` attribute) while the modal is open.
3350// To allow react-modal to do this, Circuit UI calls `Modal.setAppElement`
3451// with a query selector identifying the root of the app.
3552// http://reactcommunity.org/react-modal/accessibility/#app-element
3653if ( typeof window !== 'undefined' ) {
37- // These are the default app elements in Next.js, Docusaurus, CRA and Storybook.
38- const appElement =
39- document . getElementById ( '__next' ) ||
40- document . getElementById ( '__docusaurus' ) ||
41- document . getElementById ( 'root' ) ||
42- document . getElementById ( 'storybook-root' ) ;
54+ const appElement = getAppElement ( ) ;
4355
4456 if ( appElement ) {
4557 ReactModal . setAppElement ( appElement ) ;
@@ -119,6 +131,10 @@ export function ModalProvider<TProps extends BaseModalProps>({
119131
120132 useEffect ( ( ) => {
121133 if ( ! activeModal ) {
134+ // Clean up after react-modal in case it fails to do so itself
135+ // https://github.com/reactjs/react-modal/issues/888#issuecomment-1158061329
136+ document . documentElement . classList . remove ( HTML_OPEN_CLASS_NAME ) ;
137+ getAppElement ( ) ?. removeAttribute ( 'aria-hidden' ) ;
122138 return undefined ;
123139 }
124140
@@ -159,8 +175,8 @@ export function ModalProvider<TProps extends BaseModalProps>({
159175 key = { id }
160176 isOpen = { ! transition }
161177 onClose = { ( ) => removeModal ( modal ) }
162- portalClassName = "cui-modal-portal"
163- htmlOpenClassName = "cui-modal-open"
178+ portalClassName = { PORTAL_CLASS_NAME }
179+ htmlOpenClassName = { HTML_OPEN_CLASS_NAME }
164180 bodyOpenClassName = ""
165181 />
166182 ) ;
0 commit comments