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

How to allow scrolling on modal if window is too small

Open johnwiseheart opened this issue 7 years ago • 19 comments

Summary:

Hey, I'm having trouble with some styling of this library. I know its not a bug per-se, but figured it might be good to explore if anyone else has had or solved this issue. By default, the styling of the modal is not responsive, in that if you make the window height less than the modal height, you're not able to scroll the modal. This can be fixed by using a fixed height modal, but using a fixed height modal is restrictive on larger screens.

After some testing, I feel like there is a good solution to this using flexbox, but I haven't managed to find it yet.

TL;DR I'm trying to have a modal fit to its contents, but scroll if the window is too small.

Expected Behaviour

I'm trying to get the modal to function similarly to this codepen: https://codepen.io/anon/pen/Rodxjx

johnwiseheart avatar Dec 22 '16 00:12 johnwiseheart

@johnwiseheart there is PR #281 which I think It will allow the content of overlay to scroll (modal is inside the overlay).

diasbruno avatar Dec 26 '16 13:12 diasbruno

I solved the problem by giving the modal max-height: 100vh (that is the height of the viewport) and an overflow-y: auto. This way, if the height of the modal is more than the height of the viewport (for example when you bring up the keyboard to fill a text input) the modal adjusts its height to the height of the viewport, allowing you to scroll.

igghera avatar May 23 '18 17:05 igghera

This fixes it:

ReactModal.defaultStyles = {} // Flushes all of react-modal's styles
.ReactModal__Html--open,
.ReactModal__Body--open {
  overflow: hidden; /* prevents background page from scrolling when the modal is open */
}

.ReactModal__Overlay {
  position: fixed;
  z-index: 999999;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
}

.ReactModal__Content {
  background: white;
  width: 50rem;
  max-width: calc(100vw - 2rem);
  max-height: calc(100vh - 2rem);
  box-shadow: 0 0 30px 0 rgba(0, 0, 0, 0.25);
  overflow-y: auto;
  position: relative;
}

.modal-close-btn {
  cursor: pointer;
  top: 1.5rem;
  right: 1.5rem;
  position: absolute;
  width: 3rem;
  height: 3rem;
}

tbh the maintainers could/should do a major bump and assign .ReactModal__Overlay's styles to .ReactModalPortal, then assign .ReactModal__Content's styles to .ReactModal__Overlay.

Then they could get rid of the .ReactModal__Overlay <div> all together while fixing this gross scrolling bug.

corysimmons avatar Jun 04 '19 10:06 corysimmons

Hey @corysimmons, thanks for having a look at this. Can you try to make a PR to show how this would work?

diasbruno avatar Jun 04 '19 12:06 diasbruno

@diasbruno Yup sure can. Busy the next few days but might have some time over the weekend to prepare something. It's really not much more than what I posted above, but happy to PR. Adding this to my GH Todo. If I forget by this weekend, someone ping me.

corysimmons avatar Jun 04 '19 15:06 corysimmons

Sorry, still working on work-work stuff... 😩

Here's what I've got:

Code I'm using: https://gist.github.com/corysimmons/c1adcc4af71e7d9eb9ced0437bd208d6

The relevant bit:

.ReactModal__Html--open,
.ReactModal__Body--open {
  overflow: hidden;
}

.ReactModal__Overlay {
  position: fixed;
  z-index: 999999;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
}

.ReactModal__Content {
  background: white;
  outline: none;
  width: 50rem;
  max-width: calc(100vw - 2rem);
  max-height: calc(100vh - 2rem);
  box-shadow: 0 0 34px 0 rgba(0, 0, 0, 0.24);
  overflow-y: auto;
  position: relative;
}

My current approach isn't getting rid of the superfluous wrapping div. I think it's 100% possible to get rid of .ReactModal__Overlay and just put those styles directly on .ReactModalPortal.

corysimmons avatar Jun 08 '19 15:06 corysimmons

Did anyone ever figure this out?

justinledelson avatar Apr 30 '21 19:04 justinledelson

@justinledelson It's insane you commented on this. I literally just implemented this and was looking at this issue for my Gist after years. Anyway, my Gist still works great. Just copy/paste it and go from there.

corysimmons avatar Apr 30 '21 20:04 corysimmons

@corysimmons's implementation also works, but I'd recommend this way just to separate the modal from the scroll component.

How to make a scrollable container

react-modal is responsible to provide a frame where you can add your content.

To add a scroll, you can add these elements and styles.

<Modal ...>
   <div className="scroll-component">
      <div className="scroll-content">
          <Content ... />
      </div>
   </div>
</Modal>

The .scroll-component must have the save frame size as the .ReactModal__Content.

.scroll-component {
   width: 100%;
   height: 100%;
   overflow-y: auto;
}

.scroll-content { /* doesn't need anything... */ }

diasbruno avatar Apr 30 '21 21:04 diasbruno

I'm closing this issue, since it's not react-modal responsibility. Please, feel free to reopen if none of the suggestions works or any questions.

diasbruno avatar Apr 30 '21 21:04 diasbruno

/------------------------css----------------------------/

 .overlay {
  position: fixed;
  z-index: 1020;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(255, 255, 255, 0.75);
  display: flex;
  align-items: center;
  justify-content: center;
}

.content {
  background: white;
  width: 45rem;
  max-width: calc(100vw - 2rem);
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  position: relative;
  border: 1px solid #ccc;
  border-radius: 0.3rem;
}

/--------------------------------------tsx----------------------------------------------/

 <ReactModal id={this.state.dialogId}
                       isOpen={showDialog}
                       className={'content shadow p-4'}
                       overlayClassName={'.overlay'}
                       appElement={document.getElementById('root') as HTMLElement}>

<h1>React Modal Example</h1>

</ReactModal>

/--------------------------------------tsx----------------------------------------------/

LischtschynskijDM avatar Oct 22 '21 11:10 LischtschynskijDM

@diasbruno I definitely think the ability to scroll the content area should be the responsibility of react-modal and there should be a fix & probably a major version bump (since it will probably have to change the underlying markup).

I'd argue almost every dev just want to follow the "Getting Started" docs and have a functional/responsive/scrollable/accessible modal.

corysimmons avatar Oct 22 '21 15:10 corysimmons

Let's run this scenario:

We add this new feature and bump a major version...this use case will be the new default. Now, the rest of the world may have a hard time because it may break their particular use cases and they will need to do something to start getting the updates of this new family version (and I've saw a lot of interesting use cases I'd never thought of).

react-modal is out there for a long time now and I'd say it has reached the stable point because we keep the behavior stable enough (of course, with a few bugs here and there). We keep it simple and try to maintain the single responsibility.

diasbruno avatar Oct 22 '21 15:10 diasbruno

Fair enough.

It's also possible you don't need to do a major bump and just keep the slightly bloated markup (it's really not bad, we're talking removing a single wrapping div or just leaving it alone).

But I think the project should make the content scrollable as a major version. It could break something, but in the vast majority of cases it will simply introduce a feature ("✨ Scrollable Content Area ✨"), or arguably even a patch (this is almost a bug since clipping content is a big no-no).


Ping me for review if you do end up implementing it. I'd be happy to test. There are lots of little fringe cases involving centering, padding/margins, too much/little content, too short of a viewport, different browsers/devices, what to do with select dropdowns, etc.

corysimmons avatar Oct 22 '21 15:10 corysimmons

I totally got what you're saying, and of course, we should definitely keep thinking on ways to improve. The problem is 'how can we introduce this specific features but also keep the basic usage available?'.

diasbruno avatar Oct 22 '21 15:10 diasbruno

What if we provide this as a "companion" component? 🤔

import ReactModal from 'react-modal';
import ScrollView from 'react-modal/scrollview';

function Modal(props) {
  return (
     <ReactModal {...props} contentElement={Scrollview}>
         {...}
     </ReactModal>
  );
}

This way it will bundle this component only if needed...

diasbruno avatar Oct 22 '21 16:10 diasbruno

That's totally doable but now you're bloating the API with "Oh, be sure to read this part of the docs, and add this setting to your project to be able to do this thing that 99.999% of devs will want by default."

I think major bumps are good though if they're relatively small and move the library towards being a more robust. Tons of maintainers get this wrong.

Take Python for instance. Python 2 to 3 had a lot of breaking changes and caused a lot of pain and it took people many years to eventually migrate. But what if Python 3 just introduced a couple small changes? Yes, it would break some existing projects, but they'd be simple PRs for the community to fix. And then Python 4, 5, 6, etc could continue to add small things over a long time. It would've been a much nicer experience for everyone.

Even if it is a breaking change, think about the actual use-case someone would complain:

  1. Dev makes a site with react-modal
  2. Dev upgrades react-modal
  3. The fact that the content area is scrollable now breaks their design (very unlikely but possible)
  4. They can downgrade immediately, or
  5. They can do some ever-so-slight tweak to override the scroll ability (maybe add this workaround to the release notes)

I think you might get into problems with a major bump if react-modal is a dependency on lots of other libraries (not apps, but actual libraries) and there isn't a workaround.

I guess my overall point is: don't be afraid to do major bumps as long as they are small. You definitely want devs new to react-modal to just go yarn add react-modal and it cover common use cases (like ensuring content is scrollable out of the box).

Every single modal I have ever created in my 20+ years doing web-dev, I want overflowing content to be visible.

Ultimately it's up to you and if you feel like adding a prop is the right way to go then it's not a big deal. I think I'm just pontificating about libraries in general. I want to be able to simply add a lib and it cover super common use cases without having to study some obscure docs page about it.

corysimmons avatar Oct 24 '21 15:10 corysimmons

Did anyone ever figure this out?

Those who are still wants to scroll the content, add the below piece of code in your CSS file. It worked for me.

.ReactModal__Content--after-open {
  overflow-y: scroll !important;
  max-height: 90%;
}

pforprince avatar Mar 12 '22 15:03 pforprince

thank you @pforprince . It's working well. I am using tailwindcss:

<Modal className="absolute border p-3 rounded-lg top-1/4 left-1/2 h-auto w-10/12 lg:w-1/3 bg-white overflow-y-scroll max-h-[90%]">
// code here 
</Modal>

euhansarkar avatar Jul 27 '23 12:07 euhansarkar