react-modal icon indicating copy to clipboard operation
react-modal copied to clipboard

Warning: react-modal: App element is not defined.

Open StokeMasterJack opened this issue 7 years ago • 27 comments

I upgraded my yarn version and re-ran yarn install. And now I am getting this warning.

It's strange, because nothing in my code has changed. Something in node_modules is obviously different but who knows what. I can't do a diff on node_modules because that was never check in to git.

StokeMasterJack avatar Dec 04 '17 19:12 StokeMasterJack

@StokeMasterJack we made some changes recently to api to define the app element. Can you get the log message you got?

diasbruno avatar Dec 04 '17 19:12 diasbruno

Can you check if setting Modal.setAppElement the error goes away?

Ref: https://github.com/reactjs/react-modal#app-element

diasbruno avatar Dec 04 '17 19:12 diasbruno

Here is the exact log message:

Warning: react-modal: App element is not defined. Please use Modal.setAppElement(el) or set appElement={el}. This is needed so screen readers don't see main content when modal is opened. It is not recommended, but you can opt-out by setting ariaHideApp={false}.

StokeMasterJack avatar Dec 04 '17 19:12 StokeMasterJack

Oh sorry, thought it was an error. This is related to this change #570. This is a reminder that not setting the app element will/can cause accessibility issues.

diasbruno avatar Dec 04 '17 19:12 diasbruno

So, you need to explicit tell the modal that you don't want to use the app element with ariaHideApp={false} (if that's your case).

diasbruno avatar Dec 04 '17 19:12 diasbruno

I'll keep this open. Documentation is missing for this behavior.

diasbruno avatar Dec 05 '17 13:12 diasbruno

Can this feature be explained a bit more? When I try to use it I'm getting an error like so: ReferenceError: document is not defined coming from ariaAppHider.js

Also, is there a reason this configuration can't be encapsulated into the Modal props and must use Modal.setAppElement? How are you supposed to handle the feature given multiple Modals throughout a large app in various components? Is it just one global setting that affects all Modals?

dlong500 avatar Dec 06 '17 08:12 dlong500

Ah, I think the issue was my server rendering of the app. Once I wrapped the setAppElement call in a check to make sure it was in a client/browser environment then it appears to run OK.

I'm a still a bit unsure if things are working properly though especially because the docs state "If you are doing server-side rendering, you should use this property". That doesn't seem to make sense to me because the DOM is not even available at that point yet.

dlong500 avatar Dec 06 '17 08:12 dlong500

@dlong500 The documentation related to this is outdated. Also, we need to tests how the modal will work on a SSR environment. I did some tests to get it working, but very superficial - just to make it work.

For the multiple modal case, you can use appElement attribute.

diasbruno avatar Dec 06 '17 12:12 diasbruno

I am also getting this in the console log. No code changes in terms of my use of react-modal either. Not sure why I am getting it. Warning: react-modal: App element is not defined. Please use Modal.setAppElement(el)or setappElement={el}. This is needed so screen readers don't see main content when modal is opened. It is not recommended, but you can opt-out by setting ariaHideApp={false}.

mandazi avatar Dec 18 '17 18:12 mandazi

Nevermind I just read the thread again. Looks like I need the warning is correct. We need just need to specify it.

mandazi avatar Dec 18 '17 18:12 mandazi

Hello, I got the same warning, how do you guys make use of appElement?

Is it appElement={document.getElementById('root')} where 'root' would be where the app is mounted?

amangeot avatar Jan 11 '18 22:01 amangeot

I was seeing this when the modal is unmounted without having been triggered. Adding this fixed the issue:

Modal.setAppElement('#app-base');

mockdeep avatar Jan 26 '18 20:01 mockdeep

@mockdeep Where did you add Modal.setAppElement('#app-base');

sksundram avatar Feb 10 '18 13:02 sksundram

@sksundram right now I've got it in each of the files that I'm importing Modal for rendering. I suspect you could put it just about anywhere, though, like in your top-level app.js file, as long as it is called before the modal is rendered.

import Modal from 'react-modal';
import React from 'react';

function HelpModal({isOpen, closeModal}) {
  return (
    <Modal isOpen={isOpen} onRequestClose={closeModal}>
      'modal content'
    </Modal>
  );
}

Modal.setAppElement('#app-base');

export default HelpModal;

mockdeep avatar Feb 10 '18 16:02 mockdeep

For reference, since it was a pain for me, if you are doing SSR, use the following snippet:

  if (typeof(window) !== 'undefined') {
    ReactModal.setAppElement('body')
  }

NathanielHill avatar Apr 22 '18 19:04 NathanielHill

@diasbruno I wouldn't mind preparing the documentation for the ssr and appElement subjects. If that sounds ok, If there is any specific info you want me to elaborate on while I am at it, please let me know.

For the meantime, just for reference, for the projects which use react-modal, there is no need anymore to add the safety check that @NathanielHill suggested.

Instead of doing:

if (typeof(window) !== 'undefined') {
   ReactModal.setAppElement('body')
}

It is safe enough to do:

ReactModal.setAppElement('body')

lbelinsk avatar Jun 02 '18 21:06 lbelinsk

@lbelinsk Sure, it would be really great.

diasbruno avatar Jun 02 '18 21:06 diasbruno

@NathanielHill @lbelinsk Doing ReactModal.setAppElement('body') is wrong because it sets aria-hidden property on body while the modal itself is also inside body. The point of appElement is the modal itself being outside the appElement. Otherwise you'd just make things weirder than without it. And it would not be a valid ARIA.

catamphetamine avatar Jan 07 '19 00:01 catamphetamine

@catamphetamine

Fair point. For me the issue was just setting it to begin with. If what your saying is correct, that does sound like an accessibility issue, so if your React app has a container <div> as a child of <body> then that would be a better target.

NathanielHill avatar Jan 07 '19 00:01 NathanielHill

using the react-testing-library (https://testing-library.com/) I get rid of that warning with:

import Modal from "react-modal";

const { container } = render(<MyComponent />);
Modal.setAppElement(container);

....  // to the testing, use Modal

or, if you want to test the modal component directly:

const { container, rerender } render(<MyModalComponent isOpen={false} />);
Modal.setAppElement(container);
// now the appElement is set we can show the modal component
rerender(<MyModalComponent isOpen={false} />);

....  // to the testing

ReneCode avatar Aug 25 '19 16:08 ReneCode

Adding ariaHideApp={false} to modal works for me. <Modal isOpen={this.state.modalOpen}ariaHideApp={false}> <LoginModal closeModal={() => this.openModal()}></LoginModal> </Modal>

emmy29 avatar Feb 10 '20 04:02 emmy29

Modal . setAppElement ( '#app-base' )

Solved it, in my case it was Modal.setAppElement("#root"); in the modal component

raphab3 avatar Feb 21 '22 01:02 raphab3

Got rid of the annoying logs in tests with Modal.setAppElement(document.querySelector('body')!)

patricknazar avatar Oct 01 '22 01:10 patricknazar

To all...

This is the correct behavior for react-modal as already mention on this thread.

As @catamphetamine already mention and many others that have been working with accessibility, there is an old mistake with the default app element which uses the document.body to add the aria-hidden attribute. This cause a problem because every element that is going to be hidden is a direct descendant of document.body (the modal also becomes inaccessible).

To not break users code, we decided to make setAppElement required (or use appElement on each case where you use modal), but just warn about the problem to not break stuff...

This also applies to testing. You need to properly setup your tests to use react-modal when needed.

This is an example to do that (note that you might need to change a little bit depending on the testing framework you use):

let modalNode = null;

before(() => {
  modalNode = document.createElement('div');
  modalNode.id = "modals";
  document.appendChild(modalNode);
  ReactModal.setAppElement('#app');
}):

after(() => {
   document.removeChild(modalNode);
});

diasbruno avatar Oct 03 '22 15:10 diasbruno