Bootstrap modal in React.js

You can use React-Bootstrap (https://react-bootstrap.github.io/components/modal). There is an example for modals at that link. Once you have loaded react-bootstrap, the modal component can be used as a react component:

var Modal = ReactBootstrap.Modal;

can then be used as a react component as <Modal/>.

For Bootstrap 4, there is react-strap (https://reactstrap.github.io). React-Bootstrap only supports Bootstrap 3.


getDOMNode() is deprecated. Instead use ref to access DOM element. Here is working Modal component (Bootstrap 4). Decide whether to show or not to show Modal component in parent component.

Example: https://jsfiddle.net/sqfhkdcy/

class Modal extends Component {
    constructor(props) {
        super(props);
    }
    componentDidMount() {
        $(this.modal).modal('show');
        $(this.modal).on('hidden.bs.modal', handleModalCloseClick);
    }
    render() {
        return (
            <div>
                <div className="modal fade" ref={modal=> this.modal = modal} id="exampleModal" tabIndex="-1" role="dialog" aria- labelledby="exampleModalLabel" aria-hidden="true">
                    <div className="modal-dialog" role="document">
                        <div className="modal-content">
                            <div className="modal-header">
                                <h5 className="modal-title" id="exampleModalLabel">Modal title
                                </h5>
                                <button type="button" className="close" data- dismiss="modal" aria-label="Close">
                                    <span aria-hidden="true">&times;</span>
                                </button>
                            </div>
                            <div className="modal-body">
                                ...
                            </div>
                            <div className="modal-footer">
                                <button type="button" className="btn btn-secondary" data- dismiss="modal">Close</button>
                                <button type="button" className="btn btn-primary">Save changes</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

Edit:

Here are the necessary imports to make it work:

import $ from 'jquery';
window.jQuery = $;
window.$ = $;
global.jQuery = $;

I was recently looking for a nice solution to this without adding React-Bootstrap to my project (as Bootstrap 4 is about to be released).

This is my solution: https://jsfiddle.net/16j1se1q/1/

let Modal = React.createClass({
    componentDidMount(){
        $(this.getDOMNode()).modal('show');
        $(this.getDOMNode()).on('hidden.bs.modal', this.props.handleHideModal);
    },
    render(){
        return (
          <div className="modal fade">
            <div className="modal-dialog">
              <div className="modal-content">
                <div className="modal-header">
                  <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                  <h4 className="modal-title">Modal title</h4>
                </div>
                <div className="modal-body">
                  <p>One fine body&hellip;</p>
                </div>
                <div className="modal-footer">
                  <button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
                  <button type="button" className="btn btn-primary">Save changes</button>
                </div>
              </div>
            </div>
          </div>
        )
    },
    propTypes:{
        handleHideModal: React.PropTypes.func.isRequired
    }
});



let App = React.createClass({
    getInitialState(){
        return {view: {showModal: false}}
    },
    handleHideModal(){
        this.setState({view: {showModal: false}})
    },
    handleShowModal(){
        this.setState({view: {showModal: true}})
    },
    render(){
    return(
        <div className="row">
            <button className="btn btn-default btn-block" onClick={this.handleShowModal}>Open Modal</button>
            {this.state.view.showModal ? <Modal handleHideModal={this.handleHideModal}/> : null}
        </div>
    );
  }
});

React.render(
   <App />,
    document.getElementById('container')
);

The main idea is to only render the Modal component into the React DOM when it is to be shown (in the App components render function). I keep some 'view' state that indicates whether the Modal is currently shown or not.

The 'componentDidMount' and 'componentWillUnmount' callbacks either hide or show the modal (once it is rendered into the React DOM) via Bootstrap javascript functions.

I think this solution nicely follows the React ethos but suggestions are welcome!


I've only used bootstrap cdn (css + js) to achieve "reactstrap" like solution. I've used props.children to pass dynamic data from parent to child components. You can find more about this here. In this way you have three separate components modal header, modal body and modal footer and they are totally independent from each other.


//Modal component
import React, { Component } from 'react';

export const ModalHeader = props => {
  return <div className="modal-header">{props.children}</div>;
};

export const ModalBody = props => {
  return <div className="modal-body">{props.children}</div>;
};

export const ModalFooter = props => {
  return <div className="modal-footer">{props.children}</div>;
};

class Modal extends Component {
  constructor(props) {
    super(props);
    this.state = {
      modalShow: '',
      display: 'none'
    };
    this.openModal = this.openModal.bind(this);
    this.closeModal = this.closeModal.bind(this);
  }

  openModal() {
    this.setState({
      modalShow: 'show',
      display: 'block'
    });
  }

  closeModal() {
    this.setState({
      modalShow: '',
      display: 'none'
    });
  }

  componentDidMount() {
    this.props.isOpen ? this.openModal() : this.closeModal();
  }

  componentDidUpdate(prevProps) {
    if (prevProps.isOpen !== this.props.isOpen) {
      this.props.isOpen ? this.openModal() : this.closeModal();
    }
  }

  render() {
    return (
      <div
        className={'modal fade ' + this.state.modalShow}
        tabIndex="-1"
        role="dialog"
        aria-hidden="true"
        style={{ display: this.state.display }}
      >
        <div className="modal-dialog" role="document">
          <div className="modal-content">{this.props.children}</div>
        </div>
      </div>
    );
  }
}

export default Modal;

//App component
import React, { Component } from 'react';
import Modal, { ModalHeader, ModalBody, ModalFooter } from './components/Modal';

import './App.css';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      modal: false
    };
    this.toggle = this.toggle.bind(this);
  }

  toggle() {
    this.setState({ modal: !this.state.modal });
  }

  render() {
    return (
      <div className="App">
        <h1>Bootstrap Components</h1>

        <button
          type="button"
          className="btn btn-secondary"
          onClick={this.toggle}
        >
          Modal
        </button>

        <Modal isOpen={this.state.modal}>
          <ModalHeader>
            <h3>This is modal header</h3>
            <button
              type="button"
              className="close"
              aria-label="Close"
              onClick={this.toggle}
            >
              <span aria-hidden="true">&times;</span>
            </button>
          </ModalHeader>
          <ModalBody>
            <p>This is modal body</p>
          </ModalBody>
          <ModalFooter>
            <button
              type="button"
              className="btn btn-secondary"
              onClick={this.toggle}
            >
              Close
            </button>
            <button
              type="button"
              className="btn btn-primary"
              onClick={this.toggle}
            >
              Save changes
            </button>
          </ModalFooter>
        </Modal>
      </div>
    );
  }
}

export default App;