#Modal API

#<ModalProvider>

This component provides the modal context to your app. It does not have any required props and renders nothing in the DOM. This is where the global settings are defined.

import react from 'react';
import { ModalProvider } from '@faceless-ui/modal;

export const MyApp = () = (
  <ModalProvider>
    ...
  </ModalProvider>
);

#<ModalProvider> Props

zIndex
  :  number
  |  optional

Applies z-index to the <ModalContainer>. If generateCSS is false, this prop is ignored. Defaults to 9999.

transTime
  :  number
  |  optional

The transition duration of modals and the modal container, in milliseconds. Defaults to 250.

handleParamChange
  :  boolean or function
  |  optional

If true, will set and reset the ?modal= URL parameter using pushState from the History API. If sent a callback, will execute your function with a slug for you to handle, see Routing for more details.

trapFocus
  :  boolean
  |  optional

Traps and restores focus on using focus-trap, a popular-open source package. When a modal is opened, the first tab index of the modal becomes focused, and subsequent tabs are cycled through the modal without returning back to the original document. When the modal is closed, focus is restored to the element used to open the modal. Defaults to true.

trapFocusOptions
  :  object
  |  optional

Additional options passed to focus-trap.

classPrefix
  :  string
  |  optional

Prepends onto onto every generated class name, useful for unique name-spacing within complex stylesheets.

generateCSS
  :  boolean
  |  optional

Generates a tiny CSS stylesheet (~650B), rendered at the root of the provider. This is used for core positioning and transition timing, not visual styling. Defaults to true.

minifyCSS
  :  boolean
  |  optional

Minifies the result of generateCSS. Defaults to true.

#<ModalProvider> Context

openModal(slug: string)
  :  method

Opens the given slug and fires handleParamChange.

oneModalIsOpen
  :  boolean
  |  optional

True when at least one modal has the isOpen property. The <ModalContainer> will undergo transition every time this changes.

isModalOpen(slug: string)
  :  function

A function used to determine if a particular modal is currently open.

toggleModal(slug: string)
  :  method

Takes the slug of any modal and opens or closes that modal based on its current status, using the openModal and closeModal methods.

closeAllModals()
  :  method

Closes all modals and fires handleParamChange. Unlocks all body scroll locks.

closeOnBlur
  :  boolean

Enables a click event on the <ModalContainer> that, when clicked, will close all modals.

setCloseOnBlur()
  :  method

Used internally to set the global closeOnBlur status. Fired each time a modal is opened based on its own closeOnBlur prop.

bodyScrollIsLocked
  :  boolean

The current state of body scroll lock, useful when multiple modals differ in lockBodyScroll.

setBodyScrollLock(set: boolean)
  :  method

Enables and disables scroll on the HTML body using body-scroll-lock. Fired by lockBodyScroll on each modal individually. Check bodyScrollIsLocked for the global status after overrides.

containerRef
  :  object

A reference to <ModalContainer>, where each modal portals into.

setContainerRef(ref: React.MutableRefObject<HTMLElement>)
  :  method

Used by <ModalContainer> to populate containerRef on mount.

...settings

All settings are spread into the context.

#<ModalContainer>

This component will add an element to the DOM where every modal will portal into. It will receive transition classes when any modal is opened.

import react from 'react';
import { ModalContainer } from '@faceless-ui/modal;

export const MyApp = () = (
  <ModalContainer>
    ...
  </ModalContainer>
);

#<ModalContainer> Props

htmlElement
  :  string
  |  optional

Customize the HTML element that is rendered in the DOM. Defaults to div.

...rest
  :  object
  |  optional

All other props are spread onto the DOM element as HTML attributes.

#<Modal>

Each modal is portaled into the <ModalContainer> and receives transition classes when opened or closed. The only required prop is a unique slug.

import react from 'react';
import { Modal } from '@faceless-ui/modal;

export const MyModal = () => {
  return (
    <Modal slug="my-modal">
      ...
    </Modal>
  )
};

You can also pass a function as a child to conveniently access modal context. Although could access the same context with the useModal hook, this would require a child component, see the official Rules of Hooks.

import react from 'react';
import { Modal } from '@faceless-ui/modal;

export const MyModal = () => {
  return (
    <Modal slug="my-modal">
      {(modalContext) => {
        return (
          ...
        )
      }}
    </Modal>
  )
};

#<Modal> Props

slug*
  :  string
  |  required

A unique identifier for this modal.

closeOnBlur
  :  boolean
  |  optional

Will close the modal when the user clicks outside of it. Defaults to true.

lockBodyScroll
  :  boolean
  |  optional

Will prevent the document from scrolling while the modal is open. Defaults to true.

classPrefix
  :  string
  |  optional

Prepends onto onto every generated class name, useful for unique name-spacing within complex stylesheets.

Customize the HTML element that is rendered in the DOM. Defaults to dialog.

...rest
  :  object
  |  optional

All other props are spread onto the DOM element as HTML attributes.

#<ModalToggler>

This is a button that will open or close a modal based on its current status. It's a simple wrapper around the useModal hook. It's only required prop is a unique slug.

import react from 'react';
import { ModalToggler } from '@faceless-ui/modal;

export const MyComponent = () => {
  return (
    <ModalToggler slug="my-modal">
      ...
    </ModalToggler>
  )
};

#<ModalToggler> Props

slug*
  :  string
  |  required

The unique slug of the modal to open or close.

htmlElement
  :  string
  |  optional

Customize the HTML element that is rendered in the DOM. Defaults to div.

...rest
  :  object
  |  optional

All other props are spread onto the DOM element as HTML attributes.

#useModal

This is a hook you can use to access the modal context.

import react from 'react';
import { useModal } from '@faceless-ui/modal;

export const MyComponent = () => {
  const modal = useModal();
  return (
    ...
  )
};

#asModal

For advanced setups, use this higher order component to create your own modal entirely from scratch. Wrap your React component with this HOC to have it function as a modal. It will attach the modal context into the props of the wrapped component. The second argument is the unique slug.

import react from 'react';
import { asModal } from '@faceless-ui/modal;

export const MyModal = asModal((props) => {
  const { modal } = props;
  return (
    ...
  )
}, 'my-modal');

#Accessibility

This package strictly follows the WAI-ARIA pattern for dialogs:

  • <Modal> is a <dialog> element with the following properties:
    • open is toggled true or false based on isModalOpen
    • aria-modal is true
    • aria-label is the slug of the <Modal>
  • <ModalToggler> is a <button> element with the following properties:
    • type is button
    • aria-expanded is toggled true or false based on isModalOpen
    • aria-controls is the slug of the <Modal>
    • aria-label is Open modal SLUG or Close modal SLUG based on isModalOpen
  • Focus is trapped within open modals and restored when closed, see trapFocus
  • Keyboard Escape key closes the modal
  • Clicking outside a modal closes it, see closeOnBlur

#TypeScript

All types can be directly imported.

import {
  ModalProviderProps,
  IModalContext,
  ModalContainerProps,
  ModalProps
} from '@faceless-ui/modal/dist/types';