Creating a reusable pop-up modal in React from scratch
Tags: react, webdev
Published: 2023-08-15 15:31:09

**Written by [Rahul Chhodde](https://blog.logrocket.com/author/rahulchhodde/)✏️**

A pop-up modal is a crucial UI element you can use to engage with users when you need to collect input or prompt them to take action. Advancements in frontend web development have made it easier than ever to incorporate modal dialogs into your apps. 

In this article, we will focus on utilizing the native HTML5 `<dialog>` element to construct a reusable pop-up modal component in React. Starting from scratch will allow us to explore the process in detail, including:

*   [What is a modal dialog?](#what-modal-dialog)
*   [What is a non-modal dialog?](#what-non-modal-dialog)
*   [Understanding the native HTML `<dialog>` element](#understanding-native-html-dialog-element)
*   [How to construct a modal using the `HTMLDialogElement` API](#how-construct-modal-htmldialogelement-api)
*   [Styling a modal powered by the HTML `<dialog>` element](#styling-modal-html-dialog-element)
*   [Creating a pop-up modal in React using the `<dialog>` element](#creating-pop-up-modal-react-dialog-element)
*   [Using our React `Modal` component](#using-react-modal-component)
*   [Implementing the `NewsletterModal`](#implementing-newslettermodal)

You can check out the complete code for our React pop-up modal in [this GitHub repository](https://github.com/c99rahul/react-modal).

## What is a modal dialog? <a name="what-modal-dialog">

A modal dialog is a UI element that temporarily blocks the user from interacting with the rest of the application until a specific task is completed or canceled. It overlays the main interface and demands the user’s attention. 

A typical example of a modal is an email subscription box frequently found on blog websites. Until the user responds by subscribing or dismissing the modal, they cannot interact with the underlying content in the main interface. 

Other examples include login or signup dialogs, file upload boxes, file deletion confirmation prompts, and more. 

Modals are useful for presenting critical alerts or obtaining important user input. However, they should be used sparingly to avoid disrupting the user experience unnecessarily.

## What is a non-modal dialog? <a name="what-non-modal-dialog">

Non-modal dialogs, in contrast to modal dialogs, allow users to interact with the application while the dialog is open. They are less intrusive and do not demand immediate attention. 

Some examples of non-modal dialogs are site preference panels, help dialogs, cookie consent dialogs, context menus — the list goes on. 

This article is primarily focused on modal dialogs. Instead of expanding further on non-modals, we will maintain our emphasis on creating and discussing modal dialogs.

## Understanding the native HTML `<dialog>` element <a name="understanding-native-html-dialog-element">

Before the [native HTML `<dialog>` element was introduced](https://blog.logrocket.com/using-the-dialog-element/), developers had to rely solely on JavaScript to add the required HTML to the document to obtain the modal functionality. 

However, the native HTML `<dialog>` element is now [widely supported on modern browsers](https://caniuse.com/dialog). Thanks to the JavaScript API specifically designed for the `<dialog>` element, modal dialogs have become more semantically coherent and easier to handle. 

This also means that you no longer require a [third-party library](https://blog.logrocket.com/top-react-modal-components-for-2021/) to construct your own pop-up modals.

## How to construct a modal using the `HTMLDialogElement` API <a name="how-construct-modal-htmldialogelement-api">

The markup required to structure a native `<dialog>` element is quite straightforward. Let's explore the essential markup for constructing a modal using the `<dialog>` element:

```html
<button id="openModal">Open the modal</button>

<dialog id="modal" class="modal">
  <button id="closeModal" class="modal-close-btn">Close</button>
  <p>...</p>
  <!-- Add more elements as needed -->
</dialog>
```

Note that the modal component can be set to open by default by including the `open` attribute within the `<dialog>` element in the markup:

```html
<dialog open>
  ...
</dialog>
```

We can now utilize the JavaScript `HTMLDialogElement` API to control the visibility of the modal component that we previously defined. It's a straightforward process that involves obtaining references to the modal itself along with the buttons responsible for opening and closing it. 

By utilizing the `showModal` and `close` methods provided by the `HTMLDialogElement` API, we can easily establish the necessary connections:

```typescript
const dialog = document.getElementById('myDialog');
const openDialogButton = document.getElementById('openDialog');
const closeDialogButton = document.getElementById('closeDialog');

openDialogButton.addEventListener('click', () => {
  dialog.showModal();
});

closeDialogButton.addEventListener('click', () => {
  dialog.close();
});
```

Note that if we use `dialog.show()` instead of `dialog.showModal()`, our `<dialog>` element will behave like a non-modal element. Take a look at the following implementation. It may be simple and lacking in style, but it is fully functional. Moreover, it is much easier to integrate and provides greater semantic value compared to a comprehensive modal solution built entirely with JavaScript:

See the Pen [Simple modal example](https://codepen.io/_rahul/pen/WNYxKNY) by Rahul C ([@_rahul](https://codepen.io/_rahul)) on [CodePen](https://codepen.io).

## Styling a modal powered by the HTML `<dialog>` element <a name="styling-modal-html-dialog-element">

A modal interface powered by the HTML `<dialog>` element is easy to style and has a special pseudo-class that makes modal elements simple to select and style. I’ll keep the styling part simple for this tutorial and focus more on the basics before delving into the React implementation.

### The `:modal` pseudo-class

The [:modal CSS pseudo-class](https://blog.logrocket.com/css-modal-pseudo-selector/) was specifically designed for UI elements with modal-like properties. It enables easy selection of a dialog displayed as a modal and the application of appropriate styles to it:

```css
dialog {
  /* Styles for dialogs that carry both modal and non-modal behaviors */
}

dialog:modal {
  /* Styles for dialogs that carry modal behavior */
}

dialog:not(:modal) {
  /* Styles for dialogs that carry non-modal behavior */
}
```

The choice between these approaches — selecting an element directly to set defaults, selecting its states to apply state-specific styles, or using CSS classes to style the components — is entirely subjective. 

Each method offers different advantages, so the most suitable approach for styling will depend on the developer’s preference and the project’s operating procedure. I’ll go the CSS classes route to style our modal. 

Let's enhance it by incorporating rounded corners, spacing, a drop shadow, and some layout properties. You can add or customize these properties according to your specific needs:

```css
.modal {
  position: relative;
  max-width: 20rem;
  padding: 2rem;
  border: 0;
  border-radius: 0.5rem;
  box-shadow: 0 0 0.5rem 0.25rem hsl(0 0% 0% / 10%);
}
```

Additionally, we'll position the **Close** button in the top right corner so that it doesn’t interfere with the modal content. Further, we'll set some default styles for the buttons and input fields used in our application:

```css
.modal-close-btn {
  font-size: .75em;
  position: absolute;
  top: .25em;
  right: .25em;
}

input[type="text"],
input[type="email"],
input[type="password"],
button {
  padding: 0.5em;
  font: inherit;
  line-height: 1;
}

button {
  cursor: pointer;
}
```

### The `::backdrop` pseudo-element

When using traditional modal components, a backdrop area typically appears when the modal is displayed. This backdrop acts as a click trap, preventing interaction with elements in the background and focusing solely on the modal component. 

To emulate this functionality, the native `<dialog>` element introduces the CSS `::backdrop` pseudo-element. Here's an example illustrating its usage:

```css
.modal::backdrop {
  background: hsl(0 0% 0% / 50%);
}
```

The user agent style sheet will automatically apply default styles to the backdrop pseudo-element of dialog elements with a fixed position, spanning the full height and width of the viewport. 

The backdrop feature will not function for non-modal dialog elements, as this type of element allows users to interact with the underlying content while the dialog is open. 

The following example showcases an example implementation of all the aforementioned styling. Click the "Open the modal" button to observe the functionality in action:

See the Pen [Custom styled modal demo](https://codepen.io/_rahul/pen/eYQzLQM) by Rahul C ([@_rahul](https://codepen.io/_rahul)) on [CodePen](https://codepen.io).

Notice how the previously mentioned backdrop area works. When the modal is open, you’re not able to click on anything in the background until you click the **Close** button.

## Creating a pop-up modal in React using the `<dialog>` element <a name="creating-pop-up-modal-react-dialog-element">

Now that we understand the basic HTML structure and styles of our pop-up modal component, let's transfer this knowledge to React by creating a new React project. 

In this example, I'll be using React with TypeScript, so the code provided will be TypeScript-specific. However, I also have a [JavaScript-based demo](https://stackblitz.com/edit/stackblitz-starters-tkpczr?file=src%2Fcomponents%2FDialog.jsx) of the component we are about to build that you can reference if you are using React with JavaScript instead. 

Once the React project is set up, let's create a directory named `components`. Inside this directory, create a sub-directory called `Modal` to manage all of our `Modal` dialog component files. Now, let’s create a file inside the `Modal` directory called `Modal.tsx`:

```typescript
import React from "react";

const Modal: React.FC = () => {
  const modalRef = useRef<HTMLDialogElement | null>(null);

  return (
    <dialog ref={modalRef} className="modal">
      {children}
    </dialog>
  );
}

export default Modal;
```

In the above code snippet, we define the `Modal` component using the [React functional component syntax](https://blog.logrocket.com/what-are-react-pure-functional-components/). We use the `useRef` Hook to create a reference to the HTML `<dialog>` element that we could use later on in the `useEffect` Hooks. 

To make this component work, we need to consider the following points to determine the props we will need:

*   **Check open/closed state**: We need to keep track of the state of the dialog component — whether it is open or closed. We can use another Boolean prop for this purpose
*   **Decide on a close button**: We need to decide whether or not the dialog component should include a close button. This can also be controlled through a Boolean prop
*   **Define closing behavior**: We need to specify the desired behavior when the dialog is closed. This includes determining what actions or events should be triggered upon closing, which can be accomplished with a callback function as a prop
*   **Handle children appropriately:** We need to enable this component to accept other HTML nodes as children. This can be achieved by utilizing the special `props.children` prop provided by React

The above points contribute to shaping the type structure of our props, which we will construct using the TypeScript interface as illustrated below:

```typescript
interface ModalProps {
  isOpen: boolean;
  hasCloseBtn?: boolean;
  onClose?: () => void;
  children: React.ReactNode;
};
```

After planning the props for the `Modal` component, it is ideal to define a state variable to manage its opening and closing states:

```typescript
const Modal: React.FC<MOdalProps> = ({ isOpen, hasCloseBtn, onClose, children }) => {
  const [isModalOpen, setModalOpen] = useState(isOpen);
  const modalRef = useRef<HTMLDialogElement | null>(null);

  return (
    <dialog ref={modalRef} className="modal">
      {children}
    </dialog>
  );
};
```

With the basic structure of our `Modal` component in place, we can now proceed to implement the functionality for opening the modal.

### Opening the `Modal`

[The `useEffect` Hook](https://blog.logrocket.com/useeffect-hook-complete-guide/) is ideal for keeping things in sync because it enables performing side effects, such as updating states or interacting with APIs, in response to changes in specific dependencies. 

In the case of opening our modal, we can use a `useEffect` Hook that gets triggered whenever the `isOpen` prop changes. This ensures that the `isModalOpen` state stays in sync with the `isOpen` prop, allowing the component to respond accurately to external changes while maintaining consistency between the two:

```typescript
useEffect(() => {
  setModalOpen(isOpen);
}, [isOpen]);
```

Note that we are not going to take advantage of conditionally rendering elements in the DOM based on React state variables. Instead, we will use the `HTMLDialogElement` API to manage the visibility of our `Modal` dialog. 

We used this same approach in the plain HTML and JavaScript example we explored above. This approach will also allow us to make the most of the built-in accessibility features provided by the native HTML `<dialog>` element. 

To implement the HTML `<dialog>` modal with React, we will utilize the `isModalOpen` state variable in conjunction with another `useEffect` Hook. This Hook will control the modal’s visibility by calling `Dialog.showModal()` when `isModalOpen` is true, effectively displaying the modal. 

Conversely, when `isModalOpen` is false, it will invoke `Dialog.close()` to hide the modal. This way, the modal’s display state will always be in sync with the value of the `isModalOpen` state variable. See the code below:

```typescript
useEffect(() => {
  const modalElement = modalRef.current;
  if (modalElement) {
    if (isModalOpen) {
      modalElement.showModal();
    } else {
      modalElement.close();
    }
  }
}, [isModalOpen]);
```

### Closing the `Modal`

We can create a utility function that incorporates the optional `onClose` callback and set `isModalOpen` to `false`. This function can be used later to easily close the `Modal` dialog in different scenarios:

```typescript
const handleCloseModal = () => {
  if (onClose) {
    onClose();
  }
  setModalOpen(false);
};
```

If you observe closely, the ability to close the modal by pressing the `escape` key is an inherent feature of the HTML5 `<dialog>` element. 

However, since we are managing the states of our `Modal` component using the `useState` Hook, we need to update it accordingly when the escape key is pressed to ensure the proper functioning of the `Modal` dialog. 

To achieve this, we can simply listen for a `KeyDown` event and call the `handleCloseModal` function, which we declared earlier, whenever the event corresponds to the `escape` key:

```typescript
const handleKeyDown = (event: React.KeyboardEvent<HTMLDialogElement>) => {
  if (event.key === "Escape") {
    handleCloseModal();
  }
};
```

This approach ensures that the modal is closed appropriately when the user presses the `escape` key and prevents any conflicts between the `HTMLDialogElement` API and React states.

### Piecing it all together

In the final steps, we will utilize the optional `hasCloseBtn` prop to include a close button inside the `Modal` component. This button will be linked to `handleCloseModal` action, which is designed to close the modal as expected. 

Additionally, we will implement the `handleKeyDown` function and associate it with the `onKeyDown` event handler for the main HTML5 `<dialog>` element that will be returned by the `Modal` component. 

See the code below:

```typescript
return (
  <dialog ref={modalRef} onKeyDown={handleKeyDown}>
    {hasCloseBtn && (
      <button className="modal-close-btn" onClick={handleCloseModal}>
        Close
      </button>
    )}
    {children}
  </dialog>
);
```

With these updates, our React `Modal` component is now fully functional and complete, making use of the powerful HTML5 `<dialog>` element and its JavaScript API.

## Using our React `Modal` component <a name="using-react-modal-component">

Now, let's put the modal dialog component to use and observe its functionality. 

For this purpose, we’ll consider one of the commonly seen modal UI elements on the web: the typical newsletter subscription modal dialog. This modal will include some form fields and invite the visitor to sign up for a newsletter subscription. 

The purpose of developing this specific component is to showcase the versatility of the modal pattern for creating various types of modals. 

Additionally, we will demonstrate how to gather and manage data in the frontend using this method. Moreover, the same data can be seamlessly transferred to either the frontend or the API as required.

### Setting up the `NewsletterModal` component

The plan is to create an additional component responsible for managing the form and its data within our newsletter modal dialog. To achieve this, let’s create a new subdirectory named `NewsletterModal` under the `components` directory. 

Within the `NewsletterModal` directory, create a new file called `NewsletterModal.tsx`, which will serve as our `NewsletterModal` component. Optionally, you can also add a `NewsletterModal.css` file to style the component according to your requirements. 

Let’s begin by importing some essential dependencies, including our `Modal` component that we finished in the previous section:

```typescript
import React, { useState, useEffect, useRef } from 'react';
import './NewsletterModal.css';
import Modal from '../Modal/Modal';
```

### Defining types and props

Our newsletter form will comprise two input fields — one to collect the user's email and the other to allow users to choose their newsletter frequency preferences. We’ll include monthly, weekly, or daily options in the latter field. 

To achieve this, we will once again utilize TypeScript interfaces. We'll also export this interface to reuse it in the main `App` component:

```typescript
export interface NewsletterModalData {
  email: string;
  frequency: string;
}
```

Based on the provided type definition, we can now set the default or initial data that our newsletter form should hold. We'll use an object to manage the data for the email and frequency fields:

```typescript
const initialNewsletterModalData: NewsletterModalData = {
  email: '',
  frequency: 'weekly',
};
```

Next, we'll define the props that our `NewsletterModal` component will receive:

```typescript
interface NewsletterModalProps {
  isOpen: boolean;
  onSubmit: (data: NewsletterModalData) => void;
  onClose: () => void;
}
```

As you can see, the `NewsletterModal` component expects three props:

*   `isOpen` — A Boolean indicating whether the modal is open or not
*   `onSubmit` — A function that will be called when the form is submitted. It takes a property of the `NewsletterModalData` type as an argument
*   `onClose` — A function that will be called when the user closes the modal

Two of these props, namely `isOpen` and `onClose`, will further be used as prop values for the `Modal` component.

### Defining the `NewsletterModal` component

Now, let's define the actual `NewsletterModal` component. It's a functional component that takes in the props defined in the `NewsletterModalProps` interface. We use object destructuring to extract these props:

```typescript
const NewsletterModal: React.FC<NewsletterModalProps> = ({
  onSubmit,
  isOpen,
  onClose,
}) => {
  // Component implementation goes here...
};
```

### Managing states and references

Next, we use the `useRef` Hook to create a reference to the input element for the email field. This reference will be used later to focus on the email input when the modal is opened. 

We also use the `useState` Hook to create a state variable to manage the form data, initializing it with `initialNewsletterModalData`. 

See the code below:

```typescript
const focusInputRef = useRef<HTMLInputElement | null>(null);
const [formState, setFormState] = useState<NewsletterModalData>(
  initialNewsletterModalData
);
```

To handle side effects when the value of `isOpen` changes, we utilize the `useEffect` Hook. If `isOpen` is `true` and the `focusInputRef` is available, not `null`, we use `setTimeout` to ensure that the focus on the email input element happens asynchronously:

```typescript
useEffect(() => {
  if (isOpen && focusInputRef.current) {
    setTimeout(() => {
      focusInputRef.current!.focus();
    }, 0);
  }
}, [isOpen]);
```

This allows the modal to be fully rendered before focusing on the input.

### Handling data input

The function `handleInputChange` is responsible for handling changes in the two form input fields — the user’s email address and newsletter frequency preferences. This function is triggered by the `onChange` event of the email input and frequency select elements:

```typescript
const handleInputChange = (
  event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
): void => {
  const { name, value } = event.target;
  setFormState((prevFormData) => ({
    ...prevFormData,
    [name]: value,
  }));
};
```

When called, the function extracts the `name` and `value` from the event's target — in other words, the form element that triggered the change. It then uses the `setFormState` state variable to update the form state. 

Additionally, the `handleInputChange` function uses the callback form of `setFormState` to correctly update the state. This preserves the previous form data using the spread operator — `...prevFormData` — and updates only the changed field:

### Handling form submission

The function `handleSubmit` is called when the form is submitted. It is triggered by the `onSubmit` event of the form:

```typescript
const handleSubmit = (event: React.FormEvent): void => {
  event.preventDefault();
  onSubmit(formState);
  setFormState(initialNewsletterModalData);
};
```

This function prevents the default form submission behavior using `event.preventDefault()` to avoid a page reload. Then, it calls the `onSubmit` function from props, passing the current `formState` as an argument to submit the form data to the parent component. 

After submission, it resets the `formState` to `initialNewsletterModalData`, effectively clearing the form inputs.

### Consuming the `Modal` component

In the JSX block, we return the `Modal` component, which will be rendered with the modal’s content. 

We use our custom `Modal` component and pass it three props — `hasCloseBtn`, `isOpen`, and `onClose`. The form elements — inputs, labels, and submit button — will be rendered within the `Modal` component:

```typescript
return (
  <Modal
    hasCloseButton={true}
    isOpen={isOpen}
    onClose={onClose}
  >
    {/* Form JSX goes here... */}
  </Modal>
);
```

Inside the `Modal` component, we render a `form` element containing two sections with labels and form elements corresponding to the `input` field and `select` dropdown. The `input` field is for the user's email, and the `select` dropdown allows the user to choose the newsletter frequency. 

We bind these elements with the `onChange` event handler to update the `formState` when the user interacts with the form. The form element has an `onSubmit` event that triggers the `handleSubmit` function when the user submits the form:

```typescript
<form onSubmit={handleSubmit}>
  <div className="form-row">
    <label htmlFor="email">Email</label>
    <input
      ref={focusInputRef}
      type="email"
      id="email"
      name="email"
      value={formState.email}
      onChange={handleInputChange}
      required
    />
  </div>
  <div className="form-row">
    <label htmlFor="digestType">Digest Type</label>
    <select
      id="digestType"
      name="digestType"
      value={formState.digestType}
      onChange={handleInputChange}
      required
    >
      <option value="daily">Daily</option>
      <option value="weekly">Weekly</option>
      <option value="monthly">Monthly</option>
    </select>
  </div>
  <div className="form-row">
    <button type="submit">Submit</button>
  </div>
</form>
```

And this concludes our `NewsletterModal` component. We can now export it as a default module and move on to the next section, where we will use it and finally see our `Modal` component in action.

## Implementing the `NewsletterModal` <a name="implementing-newslettermodal">

In our `App.tsx` file — or any parent component of your choice — let's begin by importing the necessary dependencies such as React, `useState`, `NewsletterModal`, and `NewsletterModalData`. If desired, we can also use the `App.css` or the related component stylesheet to style this parent component:

```typescript
import React, { useState } from 'react';
import NewsletterModal, { NewsletterModalData } from './components/NewsletterModal/NewsletterModal';
import './App.css';
```

As discussed earlier, `NewsletterModalData` is an interface that defines the shape of the data to be passed between components to support the data within our `NewsletterModal` component. 

Within the `App` component, we utilize the `useState` Hook to establish two state variables:

*   `isNewsletterModalOpen` — A boolean state variable that tracks whether the newsletter modal is open or not. It is initialized as `false`, meaning the modal is initially closed
*   `newsletterFormData` — A state variable that holds the form data submitted through the `NewsletterModal`. It is initialized as `null` since no data is available initially

Here’s how the code should look:

```typescript
const App: React.FC = () => {
  const [isNewsletterModalOpen, setNewsletterModalOpen] = useState<boolean>(false);
  const [newsletterFormData, setNewsletterFormData] = useState<NewsletterModalData | null>(null);
  // Rest of the component implementation goes here...
};
```

To handle the modal states, we define two functions — `handleOpenNewsletterModal` and `handleCloseNewsletterModal`. These functions are used to control the state of the `isNewsletterModalOpen` variable. 

When `handleOpenNewsletterModal` is called, it sets `isNewsletterModalOpen` to `true`, opening the newsletter modal. When `handleCloseNewsletterModal` is called, it sets `isNewsletterModalOpen` to `false`, closing the newsletter modal. 

See the code below:

```typescript
const handleOpenNewsletterModal = () => {
  setNewsletterModalOpen(true);
};

const handleCloseNewsletterModal = () => {
  setNewsletterModalOpen(false);
};
```

The `handleSubmit` function is called when the user submits the form inside the `NewsletterModal`. It takes the form data from the `NewsletterModalData` interface as an argument. 

When called, the `handleSubmit` function sets the `newsletterFormData` state variable to the submitted data. After setting the data, it calls `handleCloseNewsletterModal` to close the modal:

```typescript
e>const handleFormSubmit = (data: NewsletterModalData): void => {
  setNewsletterFormData(data);
  handleCloseNewsletterModal();
};
```

Finally, we return the JSX that will be displayed as the UI for the `App` component. 

 In the JSX, we have a `div` containing a button. When clicked, this button triggers the `handleOpenNewsletterModal` function, thereby opening the newsletter modal. 

We check if `newsletterFormData` is not `null` and if its `email` property is truthy. If both conditions are met, we render a message using the data from the `newsletterFormData`. 

Then, we render the `NewsletterModal` component, passing the necessary props — `isOpen`, `onSubmit`, and `onClose`. These props are set as follows:

*   `isOpen` — set to the value of `isNewsletterModalOpen` to determine whether the modal should be displayed or not
*   `onSubmit` — set to the `handleSubmit` function to handle form submissions
*   `onClose` — set to the `handleCloseNewsletterModal` function to close the modal when requested

See the code below:

```jsx
return (
  <>
    <div style={{ display: "flex", gap: "1em" }}>
      <button onClick={handleOpenNewsletterModal}>Open the Newsletter Modal</button>
    </div>

    {newsletterFormData && newsletterFormData.email && (
      <div className="msg-box msg-box--success">
        <b>{newsletterFormData.email}</b> requested a <b>{newsletterFormData.frequency}</b> newsletter subscription.
      </div>
    )}

    <NewsletterModal
      isOpen={isNewsletterModalOpen}
      onSubmit={handleFormSubmit}
      onClose={handleCloseNewsletterModal}
    />
  </>
);
```

That’s it! We now have our `App` component up and running, showing a button to open a functional newsletter modal. When the user submits the form with the appropriate information, that data is displayed on the main app page, and the modal is closed. 

Check out the below given CodePen demo showcasing the implementation of all the code snippets mentioned earlier:

See the Pen [Newsletter form modal demo](https://codepen.io/_rahul/pen/rNQQxjJ) by Rahul C ([@_rahul](https://codepen.io/_rahul)) on [CodePen](https://codepen.io).

For a well-organized and comprehensive version of this project, you can access [the complete code on GitHub](https://github.com/c99rahul/react-modal). Please note that this implementation is written in TypeScript, but it can be adapted to JavaScript by removing the type annotations as I did in [this StackBlitz demo here](https://stackblitz.com/edit/stackblitz-starters-tkpczr?file=src%2Fcomponents%2FDialog.jsx).

## Conclusion

Nowadays, methods for creating modal dialogs no longer rely on third-party libraries. Instead, we can utilize the widely supported native `<dialog>` element to enhance our UI modal components. 

The article provided a detailed explanation of creating such a modal component in React, which can be further extended and customized to suit the specific requirements of your project. 

If you have any questions, feel free to let me know.

---

## Get set up with LogRocket's modern React error tracking in minutes:

1. Visit https://logrocket.com/signup/ to get an app ID.
2. Install LogRocket via NPM or script tag. `LogRocket.init()` must be called client-side, not server-side.

NPM:
```bash
$ npm i --save logrocket 

// Code:

import LogRocket from 'logrocket'; 
LogRocket.init('app/id');
```
Script Tag:
```javascript
Add to your HTML:

<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
```

3.(Optional) Install plugins for deeper integrations with your stack:
*   Redux middleware
*   ngrx middleware
*   Vuex plugin

[Get started now](https://lp.logrocket.com/blg/signup)