Skip to content


Repository files navigation

React One Modal

Animated modal with advanced functionality for React framework

NPM JavaScript Style Guide Size

Why One Modal?

TL;DR: The only modal you will ever need, truly the one modal for all your user cases!

  • Easy to use API
  • Manages its own state, no more passing open state around to open or close your modal xD. Modal instace is available everywhere with getModal(key) and useModal() hook.
  • Accessibility out-of-the-box, with progressive enhancement like no other modals!
  • Feature rich, while having small package size
  • Awesome animation with high reliability!
  • Reliable, doesn't matter how many modal are opened or closed concurrently. Nothing will break! a task queue manager handle all complicated siltation in global scope for all Modal instances.
  • Bottom-Sheet mode, with drag enabled and snap to defined positions!
  • Dialog mode, which make visualizing a Notification system trivial task.
  • Window mode, make UI with floating windows all around with ease!
  • First modal with stacking context: add as many step (modal-sheets) to your modal as you like, all come with awesome transitions!
  • One Modals instance is aware of its stacking context (modal-sheets) and also aware of other Modal instance in the documents, such that it deliver accessible user interface even in complicated situation.

Nested modals!? but..

Nested modals aren’t supported as we believe them to be poor user experiences.

source: Bootstrap modal

One Modal takes different approach by making nested modal accessible and awesome user experience! While being in a stacked context by itself!

Accessibility (A11y)

One Modal follow the guidelines defined by Web Accessibility Initiative - WAI as part of ARIA - W3C specification for an accessible modal, and state-of-the-art practices that has been used by newly introduced <dialog> element.

It uses it own progressively enhanced focus management solution and helper attribute aria-modal="true" and role="dialog" to hide element from Accessibility DOM tree.

On Dialog mode: aria-modal="false and interaction with page elements is allowed, following the semantic that has been used by <dialog> element through dialog.showModal() and

Ability to pass aria-x (eg. aria-labelledby, aria-describedby, aria-label) attributes for modal-sheet html on push/transit/show. This can be added for all modal-sheets within a Modal instance by defining them in attributesSheet prop, or for a specific modal-sheet through passing attributes option when calling push/transit/show.

For more detail, please read One Modal - Focus Management.

What is new?

  • Auto load css when importing component, no need to import stylesheet separably
  • All control functions (push/pop/close/show/hide) are using promises and resolve when animation is done
  • handle all errors using setModalErrorHandler
  • Enhanced accessibility!
  • handle concurrent push/pop (Promise chaining)
  • Move to TypeScript
  • Disable page scroll when modal is open
  • Add back, next control functions to traverse the stack while keeping all components live
  • Add silent option to push, to not update the active sheet when appending the given sheet
  • Add last option to push, to always append the given modal-sheet to last position in silent mode
  • Add last option to pop, to always pop the last sheet in stack
  • Close using ESC or clicking outside the modal (Optionally)
  • Local modal, for part of the DOM tree [WIP]
  • Dialog mode [WIP]
  • Window mode, where modal-sheets should behave like window that can be interact with, change focus from one to another to make it on top of all other elements, and support dragging [WIP]

Getting Started

npm install --save react-one-modal


Create new instance of Modal on any component. This Modal instance will appear on the bottom of body element by default, and it preserves the React Context of its contents to where it has been defined.

import Modal, { bindModal } from 'react-one-modal'

const App = () => {
  const [modal, modalRef] = bindModal('my-modal')

  return (
      <button onClick={() =><MyComponent />)}>
        Show floating modal

      <Modal ref={modalRef} />

By using bindModal, you can bind this Modal instance to the given key in its argument (eg. my-modal) using the returned ref object. Then you can use modal to access the the functionality of the bounded Modal directly in this component.

To facilitate accessing your defined modals, One Modal does manage its own state. Calling getModal(key) on any component, gives access the bounded of Modal instance with the given key.

import { useModal } from 'react-one-modal'

const MyComponent = () => {
  const modal = getModal('my-modal')

  return (
      <button onClick={() => { modal.push(<MyComponentStep2 />) }}>
        Next Step

      <button onClick={() => { modal.empty() }}>

For use cases where a modal is needed for one-time use, an anonymous modal can be defined and used directly via useModal hook without binding it to any key.

import Modal, { useModal } from 'react-one-modal'

const MyComponent = () => {
  const modal = getModal()
  const [confirmModal, confirmModalRef] = useModal()

  return (

      <Modal ref={confirmModalRef} >
        <p> Are you sure  </p>
        <button onClick={() => {
          // do some action!
        <button onClick={() => { confirmModal.empty() }}>


See One Modal - API


See One Modal - Examples


See One Modal - Roadmap

One Modal and <dialog> element

One Modal should be a replacement for <dialog> html element with regards to behavior and not API, it should mimic <dialog> even in edge cases or add statement otherwise. Please find the known differences in behavior here.

MIT License © MahmoudRe


No description, website, or topics provided.






No releases published


No packages published