React dismissable context and hook with layers (nesting) support
npm install react-dismissable-layers
maintained by @voiceflow
> Context and hook to add support for nested, auto-dismissable layers. State can be globally controlled through context. Best used with react-popper.
npm i react-dismissable-layers
yarn add react-dismissable-layers
Check out the Storybook Demo to see in action.

Add on a parent component.
Use the useDismissable() hook to associate different toggleable components.
``jsx
import { useDismissable } from 'react-dismissable-layers';
// open and close
const Component = () => {
const [open, toggleOpen] = useDismissable(false);
return (
`jsx
import { DismissableLayerContext } from 'react-dismissable-layers';// close all dismissibles in context
const OtherComponent = () => {
const dismissOverlay = React.useContext(DismissableLayerContext);
const close = React.useCallback(() => {
dismissOverlay.dismissAllGlobally();
}, []);
return ;
};
`API
-
DismissableLayersGlobalProvider - global provider for Dismissable Layers, wrap the whole app to make sure the useDismissable hook works with layers.
`typescript
interface DismissableLayersGlobalProviderProps {
/**
* optional prop, the HTML-node to listen close events, default is document
*/
rootNode?: HTMLElement | Document;
} const DismissableLayersGlobalProvider = React.FC;
`
-
useDismissable - a hook to toggle and dismiss poppers.
`typescript
interface Options {
/**
* ref for the popper content, to not close on the content's [dismissEvent] action
*/
ref?: RefObject; /**
* callback which will be invoked when the popper is closed
*/
onClose?: null | VoidFunction;
/**
* event on which popper will be closed, default is
'click'
*/
dismissEvent?: DismissEventType; /**
* the popper will be closed just by the [dismissEvent] action, without any layers logic, default is
false
*/
disableLayers?: boolean; /**
* do not close on default prevented events, default is
true
*/
skipDefaultPrevented?: boolean;
} type Api = readonly [
isOpened: boolean,
/**
* function to toggle popper
*/
toggle: VoidFunction,
/**
* function to force close popper
*/
close: VoidFunction
];
const useDismissable = (defaultValue = false, options: Options = {}) => Api;
`
-
DismissableLayerContext - a context to read a dissmissable layer, in most cases shouldn't be used in app layer.
`typescript
interface DismissableLayerValue {
/**
* for internal usage only
*/
readonly _subscriber: Subscriber; /**
* root node of the dismiss layer
*/
readonly rootNode: T;
/**
* dismiss currently opened in the current layer
*/
readonly dismiss: VoidFunction;
/**
* has handler on the current layer
*/
readonly hasHandler: () => boolean;
/**
* add close handler to the current layer
*/
readonly addHandler: (eventType: DismissEventType, handler: DismissEventHandler) => void;
/**
* remove close handler from the current layer
*/
readonly removeHandler: (eventType: DismissEventType) => void;
/**
* dismiss all on all layers
*/
readonly dismissAllGlobally: VoidFunction;
/**
* has subscriber on any layer
*/
readonly hasHandlersGlobally: () => boolean;
}
const DismissableLayersGlobalProvider = React.FC;
`
-
DismissableLayerProvider - provider for Dismissable Layer, wrap the popper content to make the nested poppers works as a nested ones.
`typescript
interface DismissableLayerProviderProps {
/**
* optional prop, the HTML-node to listen close events, default is document
*/
rootNode?: HTMLElement | Document;
} const DismissableLayerProvider = React.FC;
``