skip to Main Content

I am trying to render an HTML dialog element in ReactJs. I was under the impression that it would render on top of my content. In my use case I have a gallery of photos and when a user clicks a photo I want a Modal to pop up.

import './Project.css'
export default function Project({title, thumbnail_url, images, id}){
    function toggleModal(id){
        const modal = document.getElementById(id);
        const isOpen = modal?.open;
        if (isOpen){
            modal.close()
        }
        else modal.showModal()
    }
    return(
        <>
        <div className="project" onClick={()=>toggleModal(id)}>
            <h2 className='headline project-title'>{title}</h2>
            <img src={thumbnail_url} alt="" />
            <dialog className='modal' id={id} >
            <div>Dialoge</div>
            <button onClick={()=>toggleModal(id)}>close</button>
            </dialog>
        </div>
        
    </>

I expected the dialog element to render above my photo gallery like a modal yet it renders below the rest of the page content. Do I need to use a ReactJa portal for an HTML dialog?

2

Answers


  1. In fact, the ReactJs isn’t VanillaJs DOM manipulating. You have to use useState and change the state to toggle. Because the first load has happened once in the VDOM and then ReactDOM did colligate the VDOM to the main DOM.

    Now for any change, some re-rendering should be happened. And here it will be possible by using useState.

    Another thing, for choosing an element in the VDOM/DOM it was highly recommended to use useRef.

    import './Project.css';
    import { useState, useRef } from 'react';
    
    export default function Project({title, thumbnail_url, images, id}){
        const [isOpen, setOpenClose] = useState(false);
        const dialogRef = useRef();
    
        function toggleModal(){
            if (isOpen){
                setOpenClose(false);
                dialogRef.current?.close();
            }
            else {
                setOpenClose(true);
                dialogRef.current?.showModal();
            }
        }
        return(
            <>
            <div className="project" onClick={()=>toggleModal(id)}>
                <h2 className='headline project-title'>{title}</h2>
                <img src={thumbnail_url} alt="" />
                <dialog className="modal" ref={dialogRef} >
                  <div>Dialoge</div>
                  <button onClick={()=>toggleModal(id)}>close</button>
                </dialog>
            </div>
            
        </>
    
    Login or Signup to reply.
  2. It seems like the dialog element is still rendered within the normal document flow, which is why it’s appearing below the rest of the page content. To achieve the behavior of a modal that overlays on top of your content, you should indeed use a React portal.

    React portals provide a way to render a component’s content outside the DOM hierarchy of its parent component. This is particularly useful for creating modals, dialogs, and other overlays that need to appear above all other content.

    Try the code below

    import React, { useState } from 'react';
    import ReactDOM from 'react-dom';
    import './Project.css';
    
    export default function Project({ title, thumbnail_url, images, id }) {
        const [isModalOpen, setIsModalOpen] = useState(false);
    
        function toggleModal() {
            setIsModalOpen(!isModalOpen);
        }
    
        return (
            <>
                <div className="project" onClick={toggleModal}>
                    <h2 className='headline project-title'>{title}</h2>
                    <img src={thumbnail_url} alt="" />
                </div>
    
                {isModalOpen && ReactDOM.createPortal(
                    <dialog className='modal' open>
                        <div>Dialog Content</div>
                        <button onClick={toggleModal}>close</button>
                    </dialog>,
                    document.body
                )}
            </>
        );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search