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

How to render something outside ReactModal__Content but within ReactModal__Overlay

Open Albert-Gao opened this issue 5 years ago • 8 comments

I am using 3.11.1

Our UI requirements, is the close button of a modal is not inside the modal, but at the top-right corner of the screen.

I tried position: absolute and fixed, works on everything but some mobile Safari, it just won't show it at all, the only way is to lift the button outside the ReactModal__Content div

Anyway to render something outside the ReactModal__Content

Albert-Gao avatar Dec 06 '19 00:12 Albert-Gao

you can try this:

<ReactModal isOpen>
    <span style={{ position: 'fixed', right: 1, top: 1 }}>X</span>
    <div>your content</div>
</ReactModal>

llorentegerman avatar Dec 06 '19 01:12 llorentegerman

Thanks, tried, but some iOS safari will hate this, I think Apple honors HTML structure more than position: fixed, as long as it is inside, it won't render it outside.

Albert-Gao avatar Dec 06 '19 07:12 Albert-Gao

you are right, but try with overflow: 'none' for content styles

<ReactModal isOpen
    style={{
        content: {
            overflow: 'none'
        }
    }}
>
    <span style={{ position: 'fixed', right: 1, top: 1 }}>X</span>
    <div>your content</div>
</ReactModal>

this worked for me

llorentegerman avatar Dec 10 '19 00:12 llorentegerman

I would really like a way to do this without having to resort to fixed positioning. I would like to use non-fixed position for the elements inside my overlay:

  • close button
  • previous page button
  • next page button
  • modal content

OliverJAsh avatar Dec 18 '19 14:12 OliverJAsh

Actually, tried fixed, as I mentioned when posted, but some version of safari does not like it, absolute is better but still has its incompatibility with some devices, will just use absolute for now.

A fully control of the content would be better. Otherwise, it will have this constraint of having everything inside a box. But in my context, all the control buttons, back button, close button, they are outside the modal box, look like they are on the overlay.

Albert-Gao avatar Dec 19 '19 11:12 Albert-Gao

You can always use display: contents (At least for newer-ish browsers) to essentially "omit" ReactModal__Content from the rendering (Big quotes around "omit" btw) https://caniuse.com/#feat=css-display-contents

const customStyles = {
  content: {
    display: "contents",
    borderWidth: 0,
    padding: 0,
    margin: 0
  }
};

(.....)

const MyModal = () => (
	<Modal style={customStyles}>
		<TheActualContentComponent />
	</Modal>
)

fforres avatar Mar 08 '20 07:03 fforres

You can work around this by grabbing a ref to the overlay and rendering your content there with a portal. Incomplete example:

const MyModal: React.FC = () => {
  const [overlayDiv, setOverlayDiv] = useState<HTMLDivElement | null>(null);

  return (
    <ReactModal overlayRef={setOverlayDiv}>
      {overlayDiv &&
        ReactDOM.createPortal(
          <button onClick={/* handle the close button click */} />,
          overlayDiv
        )}
      {/* modal content goes here */}
    </ReactModal>
  );
};

Note that this will likely not play together perfectly with react-modal's tab handling.

fo-fo avatar Jun 12 '20 12:06 fo-fo

Sorry for bumping an old thread, but in case anyone was trying to figure it out: I think you can do this now using the custom overlayElement prop.

An example of it is in the tests: https://github.com/reactjs/react-modal/blob/827796d48e7d4c74b4362cf90955e162082ee46d/specs/Modal.spec.js#L309-L321

// Custom overlay element to hold the close button outside of the actual modal
  const OverlayElement = (
    props: JSX.IntrinsicAttributes &
      ClassAttributes<HTMLDivElement> &
      HTMLAttributes<HTMLDivElement>,
    contentElement:
      | string
      | number
      | boolean
      | ReactElement<any, string | JSXElementConstructor<any>>
      | ReactFragment
      | ReactPortal
      | null
      | undefined
  ) => {
    return (
      <div
        {...props}
      >
          <CloseIcon 
            onClick={closeModal}
            position="absolute"
            right="20px"
            top="20px" />
        {contentElement}
      </div>
    );
  };


const MyModal = () => <Modal overlayElement={OverlayElement}>this is my modal!</Modal>

timngyn avatar Jul 18 '22 18:07 timngyn