Components
Modal

Modal

The modal component provides the functionality to toggle dialogs that overlays the main content.

Usage

In the usage examples below, we use the Portal component to render the modal into a different part of the DOM and the TrapFocus component to trap keyboard focus inside the modal and to return focus to the previously focused element. This is not required, but it's recommended to avoid styling issues and increase accessibility.

import { useModal } from '@norr/components';
import { Portal } from './Portal';
import { TrapFocus } from './TrapFocus';
 
const Component = () => {
  const {
    modalProps,
    modalTriggerProps,
    modalCloseProps,
    modalIsOpen,
  } = useModal<HTMLDivElement>();
 
  return (
    <>
      <button {...modalTriggerProps}>Trigger modal</button>
      {modalIsOpen && (
        <Portal>
          <TrapFocus style={{ position: 'fixed', zIndex: 1337, inset: 0 }}>
            <div {...modalProps} style={{ backgroundColor: 'teal' }}>
              <span>Modal content.</span>
              <button {...modalCloseProps}>Close modal</button>
            </div>
          </TrapFocus>
        </Portal>
      )}
    </>
  );
};

Click outside

The component is using useClickOutside() under the hood, so by default will the modal be closed when the user clicks outside of the modal (where you spread {...modalProps}). This can be disabled by setting the disableClickOutside prop to true.

import { useModal } from '@norr/components';
import { Portal } from './Portal';
import { TrapFocus } from './TrapFocus';
 
const Component = () => {
  const {
    modalProps,
    modalTriggerProps,
    modalCloseProps,
    modalIsOpen,
  } = useModal<HTMLDivElement>({
    disableClickOutside: true,
  });
 
  return (
    <>
      <button {...modalTriggerProps}>Trigger modal</button>
      {modalIsOpen && (
        <Portal>
          <TrapFocus style={{ position: 'fixed', zIndex: 1337, inset: 0 }}>
            <div {...modalProps} style={{ backgroundColor: 'teal' }}>
              <span>Will not be closed when clicked outside.</span>
              <button {...modalCloseProps}>Close modal</button>
            </div>
          </TrapFocus>
        </Portal>
      )}
    </>
  );
};

Escape key

The component is using useEventListener() under the hood to listen for when the escape key is pressed, so by default will the modal be closed when the user presses the escape key. This can be disabled by setting the disableEscapeKey prop to true.

import { useModal } from '@norr/components';
import { Portal } from './Portal';
import { TrapFocus } from './TrapFocus';
 
const Component = () => {
  const {
    modalProps,
    modalTriggerProps,
    modalCloseProps,
    modalIsOpen,
  } = useModal<HTMLDivElement>({
    disableEscapeKey: true,
  });
 
  return (
    <>
      <button {...modalTriggerProps}>Trigger modal</button>
      {modalIsOpen && (
        <Portal>
          <TrapFocus style={{ position: 'fixed', zIndex: 1337, inset: 0 }}>
            <div {...modalProps} style={{ backgroundColor: 'teal' }}>
              <span>Will not be closed when escape key is pressed.</span>
              <button {...modalCloseProps}>Close modal</button>
            </div>
          </TrapFocus>
        </Portal>
      )}
    </>
  );
};

Prevent scroll

The component is using usePreventScroll() under the hood to prevent scroll when the modal is open. This can be disabled by setting the disablePreventScroll prop to true.

import { useModal } from '@norr/components';
import { Portal } from './Portal';
import { TrapFocus } from './TrapFocus';
 
const Component = () => {
  const {
    modalProps,
    modalTriggerProps,
    modalCloseProps,
    modalIsOpen,
  } = useModal<HTMLDivElement>({
    disablePreventScroll: true,
  });
 
  return (
    <>
      <button {...modalTriggerProps}>Trigger modal</button>
      {modalIsOpen && (
        <Portal>
          <TrapFocus style={{ position: 'fixed', zIndex: 1337, inset: 0 }}>
            <div {...modalProps} style={{ backgroundColor: 'teal' }}>
              <span>You can scroll behind the modal.</span>
              <button {...modalCloseProps}>Close modal</button>
            </div>
          </TrapFocus>
        </Portal>
      )}
    </>
  );
};