Barcelona Code School

JavaScript made me do it / Est. 2015

How to show a pop-up only once with React, localStorage and Material UI modal

material ui modal on top over main content

Imagine we have a scenario where user comes to a website and has to see a pop-up or modal with some information and has to click it to see the main content.

For example, agree to Terms and Conditions, read an important warning or merely see a call to action.

But to make it less annoying, we only want to show it once to a new user and hide it for the returning users...

This can be easily done with localStorage where we can keep the data about user clicks on the pop-up.

The way it will work would be the following:

1: New user comes to the website

2: Our component renders

3: We check if we have data in localStorage about this user already clicked on the pop-up

4: If we do not have it, then in the state of component we set data displayPopUp to be true

4a: Once user clicked to close pop-up we set localStorage to popUpClickd to be true and state displayPopUp to be false

5: If we do have it we set state to displayPopUp to be false

First in our react component we will import modal:

// import useEffect and useState
import { useEffect, useState } from "react";
// import modal from material UI
import { Modal, Box } from "@mui/material";

Remember to install @mui/material with npm i @mui/material

Then let's declare a component with modal inside:

export default function Home() {
    // state variable to decide if we should render pop-up
  const [displayPopUp, setDisplayPopUp] = useState(true);

  // when pop-up is closed this function triggers, we pass it to 'onClose' property of the modal
  const closePopUp = () => {
    // setting key "seenPopUp" with value true into localStorage
    localStorage.setItem("seenPopUp", true);
    // setting state to false to not display pop-up
    setDisplayPopUp(false);
  };

  return (
    <>
      <div>
{/* conditional rendering, if displayPopUp is truthy we will show the modal */}
        {displayPopUp && (
          <Modal
            open={true}
// once pop-up will close "closePopUp" function will be executed
            onClose={closePopUp}
            aria-labelledby="modal-modal-title"
            aria-describedby="modal-modal-description"
          >
            <Box sx={style}>
{/* what user will see in the modal is defined below */}
              <h1>Very important message</h1>
              <h3>Just press OK button to never see it again</h3>
              <button onClick={closePopUp}>OK</button>
            </Box>
          </Modal>
        )}
      </div>
{/* this is the main content of this page */}
      <div>
        <h1>The main content</h1>
      </div>
    </>
  );
}

This will successfully render the page, display pop-up, close it when user clicks and save true in the key seenPopUp in the localStorage of a browser.

But now every time we refresh the page the pop-up will appear again although we've already seen it.

To solve this let's add the last step: useEffect to check if we have seenPopUp in localStorage:

  // the useEffect to trigger on first render and check if in the localStorage we already have data about user seen and closed the pop-up
  useEffect(() => {
    // getting value of "seenPopUp" key from localStorage
    let returningUser = localStorage.getItem("seenPopUp");
    // if it's not there, for a new user, it will be null
    // if it's there it will be boolean true
    // setting the opposite to state, false for returning user, true for a new user
    setDisplayPopUp(!returningUser);
  }, []);

Now the final code for this entire component will look like this:

// import useEffect and useState
import { useEffect, useState } from "react";
// import modal from material UI
import { Modal, Box } from "@mui/material";

// write some style to pass into modal
const style = {
  fontFamily: "Montserrat",
  position: "absolute",
  top: "50%",
  left: "50%",
  transform: "translate(-50%, -50%)",
  width: 300,
  height: 200,
  border: "10px solid hotpink",
  boxShadow: 24,
  padding: 5,
  textAlign: "center",
  background: "#de4899"
};

export default function Home() {
  const [displayPopUp, setDisplayPopUp] = useState(true);

  // when pop-up is closed this function triggers
  const closePopUp = () => {
    // setting key "seenPopUp" with value true into localStorage
    localStorage.setItem("seenPopUp", true);
    // setting state to false to not display pop-up
    setDisplayPopUp(false);
  };

  // the useEffect to trigger on first render and check if in the localStorage we already have data about user seen and closed the pop-up
  useEffect(() => {
    // getting value of "seenPopUp" key from localStorage
    let returningUser = localStorage.getItem("seenPopUp");
    // if it's not there, for a new user, it will be null
    // if it's there it will be boolean true
    // setting the opposite to state, false for returning user, true for a new user
    setDisplayPopUp(!returningUser);
  }, []);

  return (
    <>
      <div>
{/* conditional rendering, if displayPopUp is truthy we will show the modal */}
        {displayPopUp && (
          <Modal
            open={true}
// once pop-up will close "closePopUp" function will be executed
            onClose={closePopUp}
            aria-labelledby="modal-modal-title"
            aria-describedby="modal-modal-description"
          >
{/* in the line below we pass our custom styles object to the modal via 'sx' prop*/}
            <Box sx={style}>
{/* what user will see in the modal is defined below */}
              <h1>Very important message</h1>
              <h3>Just press OK button to never see it again</h3>
              <button onClick={closePopUp}>OK</button>
            </Box>
          </Modal>
        )}
      </div>
{/* this is the main content of this page */}
      <div>
        <h1>The main content</h1>
      </div>
    </>
  );
}

Et voilà!

Please remember, that localStorage belongs to a specific browser, so if a user open this page in Safari, they will not see pop-up next time they open the page in the same Safari. But if they will open the page in another browser, for example in Google Chrome, they will see the pop-up again.

Link to the sandbox with code

Cheers!




Back to posts