API Reference

Everything exported by react-snappy-modal 1.2, with the exact behavior of each call.

Exports

The default export is the SnappyModal class with static methods. The provider and the hooks are named exports.

tsx
1import SnappyModal, {
2  SnappyModalProvider,
3  useCurrentModal,
4  useSnappyModalState,
5} from 'react-snappy-modal';

SnappyModal.show(component, options?)

Renders component as a new modal and returns a Promise<any> that settles when that modal closes. Every call creates a new modal with its own modalId; calling it while another modal is open stacks the new one on top instead of replacing it.

options is merged over the defaults listed in the options table below.

tsx
1const result = await SnappyModal.show(<MyModal />, { layer: 1 });

SnappyModal.close(value?, layerOrId = 0)

Closes one modal and resolves its Promise with value. layerOrId picks the target: a number (or numeric string) means a layer, anything else is treated as a modalId. The default is layer 0.

When several modals share the target layer, close() closes the one that was opened first on that layer, not the newest. If nothing matches, the call does nothing and does not throw.

tsx
1SnappyModal.close('done');          // first modal on layer 0
2SnappyModal.close('done', 1);       // first modal on layer 1
3SnappyModal.close('done', modalId); // one specific modal

SnappyModal.throw(error?, layerOrId = 0)

Works like close() but rejects the Promise with error. Use it only when the caller should treat the outcome as a failure, and always pair it with try/catch; otherwise the rejection is reported as unhandled.

tsx
1try {
2  await SnappyModal.show(<UploadModal />);
3} catch (error) {
4  // SnappyModal.throw(new Error('Upload failed')) lands here
5}

SnappyModal.isShow()

Returns true while at least one modal is open. It reads the state once and does not cause re-renders. Use useSnappyModalState() when a component has to react to changes.

tsx
1if (!SnappyModal.isShow()) {
2  SnappyModal.show(<Welcome />);
3}

useCurrentModal()

Only available inside a component rendered by show(). Returns resolveModal(value), rejectModal(error), the modal's layer, and its modalId.

resolveModal and rejectModal target the modal they were rendered in by ID, so they stay correct even when several modals share a layer. Prefer them over the static methods inside modal components.

tsx
1function Confirm() {
2  const { resolveModal, rejectModal, layer, modalId } = useCurrentModal();
3  return <button onClick={() => resolveModal(true)}>OK</button>;
4}

useSnappyModalState()

Subscribes to the modal stack and re-renders when a modal opens or closes. isShow is true while any modal is open, and modalProgress lists the open modals in render order, each with its modalId and resolved options.

tsx
1function ModalCount() {
2  const { isShow, modalProgress } = useSnappyModalState();
3  return isShow ? <span>{modalProgress.length} open</span> : null;
4}

<SnappyModalProvider>

Renders every open modal after its children and applies the scroll lock. Mount it exactly once near the root of your app.

tsx
1<SnappyModalProvider>
2  <App />
3</SnappyModalProvider>

Options

Pass options as the second argument of show(). Each modal keeps its own options.

OptionTypeDefaultDescription
allowOutsideClickbooleantrueWhen true, clicking outside the content closes the modal and resolves its Promise with undefined. Set it to false when the user must make an explicit choice.
allowScrollbooleanfalseWhen false, the page behind is locked while the modal is open and the scroll position is restored on close. The lock stays on while any open modal has allowScroll: false.
backdropboolean | stringtruetrue dims the page behind the modal; false removes the dimming. The full-screen click area stays either way, so outside clicks still follow allowOutsideClick.
positionstring'center'Where the content sits on a 3×3 grid: top-left, top-center, top-right, center-left, center, center-right, bottom-left, bottom-center, bottom-right.
zIndexnumber1000CSS z-index of the modal area. When omitted, the stylesheet default of 1000 applies.
layernumber0Stacking group. Open modals are sorted by layer, higher layers render on top, and close(value, layer) targets a layer.
classNamestring-Extra class name added to the content wrapper (.snappy-modal-content).
styleReact.CSSProperties-Inline style applied to the content wrapper.

Custom backdrop color

In version 1.2.1, passing a string as backdrop sets the --snappy-modal-backdrop CSS variable, but the bundled stylesheet reads --snappy-modal-backdrop-color, so the color is not applied. Set the color in your own CSS instead:

css
1.snappy-modal-area.backdrop {
2  --snappy-modal-backdrop-color: rgba(15, 23, 42, 0.8);
3}

How layerOrId is resolved

close() and throw() share the same lookup rules:

  • Numbers and numeric strings such as 1 or "1" are layers; any other string is a modalId.
  • Omitting the argument targets layer 0.
  • For a layer, the modal opened first on that layer is chosen.
  • If no modal matches, nothing happens.

Typing the result

show() returns Promise<any>. Wrap it in a small generic helper so callers get a precise result type. undefined stays in the union because a backdrop click resolves without a value.

tsx
1import type { ReactElement } from 'react';
2import SnappyModal from 'react-snappy-modal';
3
4type SnappyModalOptions = Parameters<typeof SnappyModal.show>[1];
5
6export function showModal<T>(
7  element: ReactElement,
8  options?: SnappyModalOptions,
9): Promise<T | undefined> {
10  return SnappyModal.show(element, options);
11}
12
13const confirmed = await showModal<boolean>(<Confirm />); // boolean | undefined
NextGuide: Async Confirmation →