reactjssimplemodal

How to programatically create a Modal in React 18


I did a function that creates a modal programatically for React 17, where you just needed to call a function to create a new modal.

It was working fantastic before the ReactDOM.render was deprecated.

Is there a way to replace the render function with something else in React 18? Right now the createRoot function is only for the root component, I want to render simple components in a specified DOM element.

It worked like this:

app.jsx

<button onClick={() => createModal(<h1>I'm a component inside a modal</h1>)}>Open Modal</button>

It handles it's own state, very useful if you want to make a bunch of modals in seconds.

This is the code:

index.js => Here is the container.

import React from 'react'
import ReactDOM from 'react-dom'
import './index.scss'
import App from './App.jsx'

ReactDOM.render(
  <React.StrictMode>
    <div id="modal-container"></div> <- This is the container
    <App />
  </React.StrictMode>,
  document.getElementById('root')
)

Modal/Modal.jsx => The modal component.

import { useState } from 'react'
import './Modal.scss'

const Modal = ({ content }) => {
    const [isOpen, setIsOpen] = useState(true)

    if (isOpen) {
        return (<>
            <div className="modal-background" onClick={() => setIsOpen(false)} />

            <div className="modal-content" >
                {content}
            </div>

            <button onClick={() => setIsOpen(false)} className="close-button" >Close</button>
        </>)
    } else return null
}

export default Modal

Modal/index.js => The call function:

import { render } from "react-dom"
import Modal from "./Modal"

const createModal = (content) => render(
    <Modal key={Math.random()} content={content} />, document.getElementById("modal-container")
)

export default createModal

Solution

  • It worked using createRoot this way, instead of render:

    Here is an example: CodeSandbox

    Modal/index.js

    import { createRoot } from 'react-dom/client'
    import Modal from "./Modal"
    
    const createModal = (content) => {
        if (!window.modalContainer) {
            window.modalContainer = createRoot(document.getElementById('modal-container'))
        }
    
        window.modalContainer.render(<Modal key={Math.random()} content={content} />)
    }
    export default createModal
    

    It checks if createRoot on the specified component has been called before, so it only call createRoot once, and the render function any time a new modal is created.

    If you have a better answer it would be awesome too. :)