0

So i have watched this great tutorial on how to create a modal: https://www.youtube.com/watch?v=9DwGahSqcEc

And I have made it work. But the problem is that the guy in the video creates both the button and the modal all at the same place, and then he calls it in his App.js as <Modal />

But in my case, I have the button in the main navbar, and when I click the button the modal opens inside the navbar, which is not optimal.

I have tried many things, but I am sadly not able to separate the button from the modal component, such that the button calls the function outside of the navbar.

The modal component looks like this:

import React, { useState } from "react";

export default function Modal() {
  const [modal, setModal] = useState(false);

  const toggleModal = () => {
    setModal(!modal);
  };

  if (modal) {
    document.body.classList.add("active-modal");
  } else {
    document.body.classList.remove("active-modal");
  }

  return (
    <>
      <button
        onClick={toggleModal}
        className="btn-modal"
        class="block text-gray-900 dark:text-white font-bold rounded-lg text-sm px-5 py-2 text-center"
        type="button"
      >
        Login
      </button>

      {modal && (
      
          <div class="relative px-4 w-full max-w-md h-full md:h-auto">
            <div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
              <div class="flex justify-end p-2">
                <button
                  className="close-modal"
                  onClick={toggleModal}
                  type="button"
                  class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-800 dark:hover:text-white"
                >
                  <svg
                    class="w-5 h-5"
                    fill="currentColor"
                    viewBox="0 0 20 20"
                    xmlns="http://www.w3.org/2000/svg"
                  >
                    <path
                      fill-rule="evenodd"
                      d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
                      clip-rule="evenodd"
                    ></path>
                  </svg>
                </button>
              </div>
              <form
                class="px-6 pb-4 space-y-6 lg:px-8 sm:pb-6 xl:pb-8"
                action="#"
              >
                <h3 class="text-xl font-medium text-gray-900 dark:text-white">
                  Sign in to our platform
                </h3>
                <div>
                  <label
                    for="email"
                    class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
                  >
                    Your email
                  </label>
                  <input
                    type="email"
                    name="email"
                    id="email"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
                    placeholder="name@company.com"
                    required
                  ></input>
                </div>
                <div>
                  <label
                    for="password"
                    class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"
                  >
                    Your password
                  </label>
                  <input
                    type="password"
                    name="password"
                    id="password"
                    placeholder="••••••••"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
                    required
                  ></input>
                </div>
                <div class="flex justify-between">
                  <div class="flex items-start">
                    <div class="flex items-center h-5">
                      <input
                        id="remember"
                        aria-describedby="remember"
                        type="checkbox"
                        class="w-4 h-4 bg-gray-50 rounded border border-gray-300 focus:ring-3 focus:ring-blue-300 dark:bg-gray-600 dark:border-gray-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800"
                        required
                      ></input>
                    </div>
                    <div class="ml-3 text-sm">
                      <label
                        for="remember"
                        class="font-medium text-gray-900 dark:text-gray-300"
                      >
                        Remember me
                      </label>
                    </div>
                  </div>
                  <a
                    href="#"
                    class="text-sm text-blue-700 hover:underline dark:text-blue-500"
                  >
                    Lost Password?
                  </a>
                </div>
                <button
                  type="submit"
                  class="w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
                >
                  Login to your account
                </button>
                <div class="text-sm font-medium text-gray-500 dark:text-gray-300">
                  Not registered?{" "}
                  <a
                    href="#"
                    class="text-blue-700 hover:underline dark:text-blue-500"
                  >
                    Create account
                  </a>
                </div>
              </form>
            </div>
          </div>
      )}
    </>
  );
}
Sermad NaJar
  • 135
  • 1
  • 5
  • 15
  • I believe the button and the modal.jsx component that has the function must be separated I just don't know how. – Sermad NaJar Mar 19 '22 at 20:18
  • I answered a similar question a while back. Modals/popups [should use portals](https://stackoverflow.com/a/71436694/1377002). – Andy Mar 19 '22 at 20:26
  • I'm having a hard time understanding exaclty what goes on in your example. Could you maybe help me in regards to my example? – Sermad NaJar Mar 19 '22 at 20:35

1 Answers1

1

That is a common issue with react which can be solved with react portals. Try to read and understand how they work, this will help you understand my answer.

Short explanation: First you have to split your modal component into a ModalButton and a Modal. Then you can use the ReactDOM.createPortal function, to render the content of the Modal component somewhere else. In my example, it will be rendered into the body element instead of the navigation.

  return ReactDOM.createPortal(
    <div>
...
    </div>,
    document.body
  );

Here is a codesandbox with a working in detail example with your code.

henk
  • 2,677
  • 2
  • 18
  • 49
  • So i've done exactly as it sais, but now it doesen't work sadly. I will link my repo, maybe you can have a look at it. I would really appreciate the help. Because I have no idea why it doesen't work when I click on the btn now. I see in the console it switches, but nothing happens. – Sermad NaJar Mar 22 '22 at 03:27
  • https://github.com/SermadNajar/Tribeto/tree/Tribeto_v.1.3.2 – Sermad NaJar Mar 22 '22 at 03:28
  • @SermadNaJar I took a look at your code, try to scroll to the bottom, there you will see the modal. While creating the portal, you have specified with the second argument `document.body` that the modal should be rendered into the `` html tag. And that is what it does. Now you have to add a position absolute to it or position it otherwise in accordance with your needs. – henk Mar 23 '22 at 17:06
  • Thanks alot, i made it work with your help! (: – Sermad NaJar Mar 23 '22 at 23:35
  • If I did answer your question, please accept it, so it can be closed and won't pull any attention anymore. Also if you like the help you get, give it a thumbs up. ;) – henk Mar 24 '22 at 07:53
  • I'm a bit new to Stackoverflow, i will try figure out how to accept and give it a like :D – Sermad NaJar Mar 24 '22 at 13:34