Security News
RubyGems.org Adds New Maintainer Role
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
react-modal-global
Advanced tools
Highly reusable React Modal that can be run from useEffect.
useEffect
hook or any other global scopeModal.open(ModalComponent, { id: "2" })
as you would render components <ModalComponent id="2" />
open
method in the modal component via useModalWindow
hookModalController
class and create your behaviorI was looking for a way to use modals in useEffect
hook without using useState
in each component and passing them to modal. I found a lot of packages with various features, but they all have some disadvantages:
title
, desc
/ header
, body
" pattern - which is not convenientSo I decided to create this package that would solve all these problems at once.
I was insipered a lot by packages like react-toastify and react-modal.
Title | Playground |
---|---|
Example of layouts usage | |
Example of usage with ChakraUI (by @laurensnl) |
Please follow steps below to use this package in your project.
Modal
To start you need to create Modal
. ModalController
controls behaviour of the modals and is used in ModalContainer
.
import { ModalController } from "react-modal-global"
export const Modal = new ModalController()
ModalContainer
is a display container for modal components (it should be placed in the root), modal components will appear here as you open them.
import React from "react"
import ReactDOM from "react-dom"
import { ModalContainer } from "react-modal-global"
import Modal from "./Modal" // Your modal.
function App() {
return (
<>
{/* ... Other components ... */}
{/* It's better if `ModalContainer` goes after all other components */}
<ModalContainer controller={Modal} />
</>
)
}
ReactDOM.render(<App />, document.getElementById("root"))
Notice that you have to have styles to keep modal closed, otherwise modal will not work as expected.
You can write your own styles or use provided be the library by importing it
import "react-modal-global/styles/modal.scss" // Imports essential styles for `ModalContainer`.
import "react-modal-global/styles/layouts.scss" // Imports optional styles for `PopupLayout` and `DrawerLayout`.
Modal component is actually a React component. Note that this should be exactly component factory not an element.
// Arrow function component
const ModalComponent = () => <>:3</>
// Plain function component
function ModalComponent() {
return <>:3</>
}
// Class component
import { Component } from "react"
class ModalComponent extends Component {
render() { return <>:3</> }
}
modal context
This allows a component to access modal window context inside it to see what props were passed in open
method.
This also can be used to close modal window from inside (e.g. close on button click). Or you can listen to close
event and run a cleanup function.
function ModalComponent() {
const modal = useModalWindow() // Getting modal context of a modal window related to this component.
return (
<>
<h2>Title</h2>
<p>Content text</p>
<button type="button" onClick={modal.close}>close</button>
</>
)
}
Modal components can be templates for other modal components. See example here
Recommended naming is [Popup, Dialog or Modal] + [Name of a modal] => DialogPurchase.
This is how you disaply your modal components
// Import default styles.
import "react-modal-global/styles/modal.scss"
import { Modal } from "react-modal-global"
import PopupLogin from "./PopupLogin"
function HomeView() {
function showLoginPopup() {
Modal.open(PopupLogin, { /* Probably your options? */ })
}
return (
<>
<h2>Title</h2>
<p>Content text</p>
<button type="button" onClick={showLoginPopup}>Show login popup</button>
</>
)
}
Although you can create your own layout (i.e. component) to pass title
, description
and other required/optional props. This library encourages using only component and its props to open modals as just how you would use it in a tree.
So instead of
Modal.open(PopupGeneral, {
title: "Login",
description: "Please login to continue"
})
Include them in the component itself. Of course you will need to create more components, but this is the way to go.
Modal.open(PopupLogin)
Or you can create types of your modal components and pass them to open
method.
Modal.open(PopupAuth, {
type: "login" // or "register"
})
Eventually, this is up to you to decide, it always depends on your case.
To use various modal types (Dialog, Popup, Drawer), you create your own layout
for each one, advised naming is [Type][Name] => DrawerLayout
.
To create your first Popup
modal try this
import { FormEvent } from "react"
import { useModalWindow } from "react-modal-global"
import PopupLayout from "../modal/layouts/PopupLayout/PopupLayout"
function PopupMyFirst() {
const modal = useModalWindow()
function onSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault()
const target = event.currentTarget
const ageInput = target.elements.namedItem("age")
alert(ageInput) // Show age
modal.close() // Then close `this modal`
}
return (
<PopupLayout>
<form onSubmit={onSubmit}>
<h2>My first popup modal</h2>
<input name="age" placeholder="Enter your `first popup modal` age" />
<button type="submit">See my age</button>
</form>
</PopupLayout>
)
}
export default PopupMyFirst
Instead of wrapping your modal components manually you can pass template
attribute to ModalContainer
, for example, PopupLayout
<ModalContainer controller={Modal} template={PopupLayout} />
Layout is a component that wraps modal component and allows to customize modal look and controls (close button, header, footer, etc.).
Layouts are used to create various modal types (Dialog, Popup, Drawer) and to customize modal controls.
For example, you can create your own PopupLayout
to use it in your Popup
modals.
Layouts should not have aria-modal
attribute and role="dialog"
because they are already set in ModalContainer
component.
You should manually add aria-labelledby
and aria-describedby
attributes to your layout.
Open
Modal.open
is a method that opens a modal. See usage for example. See options for more details.
Modal.open(ModalComponent, { /* options */ })
Close
close
Modal.close
is a method that closes a modal by its instance. This will only close one modal, since any duplicates are filtered.
Modal.close(ModalWindow)
closeByComponent
Modal.closeByComponent
is a method that closes a modal by its component. It will close all modals that use this component.
Modal.closeByComponent(ModalComponent)
closeById
Modal.closeById
is a method that closes a modal by its id. It will close all modals that have this id.
Modal.closeById("insane-id")
Since all modal ids are set to -1
by default, you can close all modals that don't have a custom id
Modal.closeById(-1)
You can use options when opening a modal with Modal.open()
.
Available options
Option | Description |
---|---|
id | Specifies id of a modal. In react it's used as a key . May be used to find and close specific modal or else. |
closable | Specifies if a modal closing is controllable internally. If false , it's supposed to mean that user should do a specific action to close. |
label | Specifies aria-label . |
layer | Specifies how modals should overlap. |
The ModalContainer
component is a container for all modals, but it's not required to use it.
So if you're not happy with the default container, you can create your own.
It depends on ModalController
and ModalContext
to work.
If you open a modal while another modal is already opened, it will be queued and will be opened after the previous one is closed.
Data will be restored if you open a modal with the same component and props after it was closed.
It also works with Modal.replace
method, which can replace props with new ones while keeping the same component and data.
Sometimes you need to open a modal on top of another modal, for example, you have a modal with a login form, and you want to open another modal with a phone confirmation on top of it but keeping the login form visible and state preserved.
This is where layer
depth comes in handy.
Modal.open(ModalComponent, {
layer: 1 // Default is 0
})
Note that layer
depth is not really a z-index, it's just a number that specifies the depth of a modal, it's used to determine which modal should be opened on top of another.
Please consider contributing to this feature, I will be happy to see your PRs or just a feedback.
There are more than one way to create modals in React.
Two the most popular are "React Tree Modal" and "Common Consumer Modal" (this is how I call it).
This is mostly known in React community, it's a modal that is rendered in a tree. There is a library called react-modal that implements this approach.
But this way has some problems, one of them is that you have to create a component, which will control your modal state (open, closed) every time for every modal, and it's not convenient.
This is an approach just consumes "title
and description
" or "header
and body
" props and renders them in a common container.
This approach lacks of flexibility, but it's easier to use. There also may be problems
Needs feedback, please contribute to GitHub Issues or leave your message to the discord server.
FAQs
Uncontrollable Global React Modal
The npm package react-modal-global receives a total of 0 weekly downloads. As such, react-modal-global popularity was classified as not popular.
We found that react-modal-global demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.
Security News
Research
Socket's threat research team has detected five malicious npm packages targeting Roblox developers, deploying malware to steal credentials and personal data.