Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Close React Modal

I'm having a lot of problems trying to figure out how to add a functioning close button to my modal - constructor/props hasn't been working and I'm not sure what to put after onClick= in the button element.

class Modal extends React.Component {

// whenever component gets rendered to the screen we create a new div assigned to this.modalTarget
	componentDidMount() {
		this.modalTarget = document.createElement('div');
		// add class name to modal target
		this.modalTarget.className = 'modal';
		// take the div we just created and append it to the body tag in doc
		document.body.appendChild(this.modalTarget);
		// call method _render
		this._render();
	}

// whenever the component's about to update we do another render
// this render makes sure that if we get a new set of components or children in the modal
// we're going to render those to the parent div as well
	componentWillUpdate() {
		this._render();
	}

// clean up - whenever the component is about to unmount from the screen
// cleans up dom when the modal is removed from the component heirarchy
	componentWillUnmount() {
		// unmounts this.props.children
		ReactDOM.unmountComponentAtNode(this.modalTarget);
		document.body.removeChild(this.modalTarget);
	}

	_render() {
		// take react dom library and render a div that contains this.props.children
		// and render it into this.modalTarget
		ReactDOM.render(
			<Provider store= {store}>
				<Router>
					<div className="modal">
						{this.props.children}
						<button>Close</button>
					</div>
				</Router>
			</Provider>,
			this.modalTarget
like image 327
Ally Fuller Avatar asked May 30 '26 13:05

Ally Fuller


1 Answers

Several issues here. First, move away from directly manipulating the DOM. React uses a virtual DOM, so you don't need to manually add or remove DOM elements. React automatically handles this DOM manipulation through the render method. Also, you'll need to control this Modal utilizing some sort of state (isOpen). It be can through React's local state or through Redux's state. Either way, it needs to be controlled and compared against. Put simply, if it's open, render the Modal, if it's closed, render null.

In addition, this Modal component can be structured to be reusable. Simply add it as a child to another stateful parent component and include whatever children you want to render inside of it.

Working example:

Edit Simple Modal


components/Example.js (parent component)

import React, { Component } from "react";
import Modal from "../Modal";
import "./styles.css";

class Example extends Component {
  state = { isOpen: false };

  handleOpenModal = () => {
    this.setState({ isOpen: true });
  };

  handleCloseModal = () => {
    this.setState({ isOpen: false });
  };

  render = () => (
    <div className="example">
      <h2>Simple Modal Example</h2>
      <button
        className="uk-button uk-button-primary uk-button-small"
        onClick={this.handleOpenModal}
      >
        Open Modal
      </button>
      <Modal isOpen={this.state.isOpen} onCloseModal={this.handleCloseModal}>
        <h1 className="title">Hello!</h1>
        <p className="subtitle">There are two ways to close this modal</p>
        <ul>
          <li>Click outside of this modal in the grey overlay area.</li>
          <li>Click the close button below.</li>
        </ul>
        <button
          className="uk-button uk-button-danger uk-button-small"
          onClick={this.handleCloseModal}
        >
          Close
        </button>
      </Modal>
    </div>
  );
}

export default Example;

components/Modal.js (child component -- this has a lot of smaller components that were separated for reusability and ease of understanding -- they're basically simple divs with some styles attached -- see notes below)

import React from "react";
import PropTypes from "prop-types";
import BackgroundOverlay from "../BackgroundOverlay"; // grey background
import ClickHandler from "../ClickHandler"; // handles clicks outside of the modal
import Container from "../Container"; // contains the modal and background
import Content from "../Content"; // renders the "children" placed inside of <Modal>...</Modal>
import ModalContainer from "../ModalContainer"; // places the modal in the center of the page

// this is a ternary operator (shorthand for "if/else" -- if cond ? then : else)
// below can be read like: if isOpen is true, then return/render the modal, else return null
const Modal = ({ children, isOpen, onCloseModal }) =>
  isOpen ? (
    <Container>
      <BackgroundOverlay />
      <ModalContainer>
        <ClickHandler isOpen={isOpen} closeModal={onCloseModal}>
          <Content>{children}</Content>
        </ClickHandler>
      </ModalContainer>
    </Container>
  ) : null;

// these proptype declarations are to ensure that passed down props are 
// consistent and are defined as expected
Modal.propTypes = {
  children: PropTypes.node.isRequired, // children must be a React node
  isOpen: PropTypes.bool.isRequired, // isOpen must be a boolean
  onCloseModal: PropTypes.func.isRequired // onCloseModal must be a function
};

export default Modal;
like image 170
Matt Carlotta Avatar answered Jun 02 '26 21:06

Matt Carlotta



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!