React-modal: Dynamic sizing of the modal

Created on 19 Aug 2015  路  14Comments  路  Source: reactjs/react-modal

Does anyone know how to dynamically size the modal? For example, if I hard-coded the width of some content to be 100px wide, and the app element that the modal is bound to is 200px wide, I want the modal to be centered in the window at 100px wide. Any ideas?

Most helpful comment

It would seem there are enough people asking for this feature. It's not sufficient to declare static CSS classes as this doesn't meet the needs of the OP - i.e. dynamic modal sizes.

It would be relatively trivial to implement additional props on the Modal component that affect the size.

All 14 comments

Here is a _hack_ I used to do a similar thing, vertically rather than horizontally.

  • Add a ref name (ie: ref='content') to your content container div.
  • Grab the height of the content container element once it is in the DOM and put it in state:
  componentDidUpdate() {
    if (window.requestAnimationFrame) {
      window.requestAnimationFrame(this.sizeDialog);
    }
    else {
      // IE <10 CYA - Note: I haven't actually tested this in IE - YMMV
      window.setTimeout(this.sizeDialog, 50);
    }
  }

  sizeDialog = () => {
    if (!this.refs.content) return;
    let contentHeight = this.refs.content.getBoundingClientRect().height;
    this.setState({
      contentHeight: contentHeight,
    });
  }

Note that use requestAnimationFrame here - the ref was not yet defined otherwise. _Maybe_ this has to do with the DOM magic react-modal does... At any rate this is a hack and I'm sure there is a better way to do this.

  • In render(), use this.state.contentHeight to style the dialog:
    const padding = 90; // adjust this to your needs
    let height = (this.state.contentHeight + padding);
    let heightPx = height + 'px';
    let heightOffset = height / 2;
    let offsetPx = heightOffset + 'px';

    const style = {
      content: {
        border: '0',
        borderRadius: '4px',
        bottom: 'auto',
        height: heightPx,  // set height
        left: '50%',
        padding: '2rem',
        position: 'fixed',
        right: 'auto',
        top: '50%', // start from center
        transform: 'translate(-50%,-' + offsetPx + ')', // adjust top "up" based on height
        width: '40%',
        maxWidth: '40rem'
      }
    };

    return (
      <Modal isOpen={this.props.show} style={style} className='dialog'>
        <div className='dialog__content' ref='content'>
        ... your content goes here ...
        </div>
      </Modal>
    );

Hope this helps.

Thanks @davidmfoley.
It works quite well.

Nice @davidmfoley

No problem.

We are now using pure CSS to size the modal, which works as long as you style the components in the modal so that they result in proper width/height, relieving the need for any requestAnimationFrame/manual coordinate math:

...
      content: {
        border: '0',
        borderRadius: '4px',
        bottom: 'auto',
        minHeight: '10rem',
        left: '50%',
        padding: '2rem',
        position: 'fixed',
        right: 'auto',
        top: '50%',
        transform: 'translate(-50%,-50%)',
        minWidth: '20rem',
        width: '80%',
        maxWidth: '60rem'
      }
...

Thanks for the pure CSS solution!

It's been a while since there was any discussion on this issue. I'm assuming that it isn't a problem anymore. If it is, feel free to re-open the issue.

Hello guys,
did you find a solution to let the modal resize to fit its content's width, centering the modal in the window, without disabling vertical scrolling of the modal ? The modal should move, not the content inside the modal.

@amangeot As David pointed out, the layout breaks if the children inside the modal exceed the dimensions of the viewport, but defining maximum dimensions for a child container in viewport units should take care of that. Using his code I ended up doing this:

.modalClass {
  position: fixed;
  top: 50%;
  right: auto;
  bottom: auto;
  left: 50%;
  transform: translate(-50%,-50%);
  outline: 0;
}

.childDiv {
  max-height: 90vh;
  max-width: 90vw;
}

At least for the image previews I am using it for, it seems to work really well, even on mobile.

I get this fixed by writing HOC where i am using refs to get content/modal height.

Link - https://gist.github.com/mohandere/b563d19f5f1c7bf027fd7129592e9ab8

Here's how I do it with my modals.

content: {
  border: '1px solid #ccc', background: '#fff',
  overflow: 'auto', WebkitOverflowScrolling: 'touch',
  borderRadius: '4px', outline: 'none', padding: '20px',
  top: '50%', left: '50%', right: 'auto', bottom: 'auto',
  marginRight: '-50%', transform: 'translate(-50%, -50%)',
}
import Modal from 'react-modal';
import PropTypes from 'prop-types';
import styled from 'styled-components';

const CustomStyles = {
  overlay: {
    backgroundColor: 'rgba(32, 40, 46, 0.5)',
    display: 'flex',
    'align-items': 'center',
  },
};

export const StyledModal = styled(Modal)`
  position: relative;
  overflow: auto;
  outline: none;
  margin: auto;
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  box-shadow: 0 5px 20px 0 rgba(0, 0, 0, 0.5);
  border-radius: 8px;
  width: 290px;
`;

<StyledModal isOpen={ isModalOpen } onRequestClose={ onCloseModal } contentLabel={ "Modal" }
                   style={ CustomStyles } >
        <InvisibleButtonWrapper/>
        <div> content here</div>
 </StyledModal>

It would seem there are enough people asking for this feature. It's not sufficient to declare static CSS classes as this doesn't meet the needs of the OP - i.e. dynamic modal sizes.

It would be relatively trivial to implement additional props on the Modal component that affect the size.

Late to the game but not following how to dynamically size the modal. What I see is that the dialog width is set to 50%, (.popup-content width:50%). That ends up being 50% of the viewport. If I constrain the width of the contents that makes the content smaller but there is still a bounding rect that is 50% of the viewport.

div class="popup-content " style="position: relative; background: rgb(255, 255, 255); width: 50%; margin: auto; border: 1px solid rgb(187, 187, 187); padding: 5px;"

What about dynamic sizing of the modal in typescript?

Was this page helpful?
0 / 5 - 0 ratings