type Modal = { ref: HTMLElement | null; prevStyle?: CSSStyleDeclaration }; type Parent = { modals: Modal[]; parentNode: Modal; }; export default class Handler { // track all the modals mounted private parent: Parent[]; constructor() { this.parent = []; } static handleStyle(parentNode: Modal) { if (parentNode.ref) { parentNode.prevStyle = { ...parentNode.ref.style }; // Apply styles here parentNode.ref.style.overflow = 'hidden'; } } static restoreStyle(parentNode: Modal) { if (parentNode.ref && parentNode.prevStyle) { // remove all styles here /** * Case:- In safari browsers undefined is not setting the css for overflow styly so added the "" as a fallback. */ parentNode.ref.style.overflow = parentNode.prevStyle.overflow || ''; } } mount(modal: Modal, parentNode: Modal = { ref: null }) { // add modal with parent if (parentNode.ref) { const parentIndex = this.parent.findIndex((node) => node.parentNode === parentNode); if (parentIndex !== -1) { this.parent[parentIndex].modals.push(modal); } else { this.parent.push({ parentNode, modals: [modal], }); } Handler.handleStyle(parentNode); } else { // get top modal, if not get the body; const parent = this.getTopModal(); parent.modals.push(modal); Handler.handleStyle(parent.parentNode); if (parent.parentNode.ref !== document.body) { this.parent.push({ parentNode: modal, modals: [], }); } else { this.parent.push(parent); } } } getTopModal(): Parent { if (this.parent.length) { return this.parent[this.parent.length - 1]; } else { return { parentNode: { ref: document.body, prevStyle: document.body.style }, modals: [] }; } } remove(modal: Modal) { const parentNode = this.parent.find((node) => node.modals.find((_modal) => _modal.ref === modal.ref)); if (parentNode) { Handler.restoreStyle(parentNode.parentNode); } } }