diff --git a/src/components/FunctionalArea/ContextMenu/ContextMenu.component.tsx b/src/components/FunctionalArea/ContextMenu/ContextMenu.component.tsx
index 973785e63078e5201eac60db07a5f1ecda9bb398..5e92826059af1ed40834e13d57ab5a60f6ac9ca5 100644
--- a/src/components/FunctionalArea/ContextMenu/ContextMenu.component.tsx
+++ b/src/components/FunctionalArea/ContextMenu/ContextMenu.component.tsx
@@ -14,6 +14,7 @@ import { ClickCoordinates } from '@/services/pluginsManager/pluginContextMenu/pl
 import { currentModelSelector } from '@/redux/models/models.selectors';
 import { mapDataLastPositionSelector } from '@/redux/map/map.selectors';
 import { DEFAULT_ZOOM } from '@/constants/map';
+import { OutsideClickWrapper } from '@/shared/OutsideClickWrapper';
 
 export const ContextMenu = (): React.ReactNode => {
   const pluginContextMenu = PluginsContextMenu.menuItems;
@@ -29,15 +30,19 @@ export const ContextMenu = (): React.ReactNode => {
     return isUnitProtIdAvailable() ? unitProtId : 'no UnitProt ID available';
   };
 
+  const closeContextMenuFunction = (): void => {
+    dispatch(closeContextMenu());
+  };
+
   const handleOpenMolArtClick = (): void => {
     if (isUnitProtIdAvailable()) {
-      dispatch(closeContextMenu());
+      closeContextMenuFunction();
       dispatch(openMolArtModalById(unitProtId));
     }
   };
 
   const handleAddCommentClick = (): void => {
-    dispatch(closeContextMenu());
+    closeContextMenuFunction();
     dispatch(openAddCommentModal());
   };
 
@@ -47,7 +52,7 @@ export const ContextMenu = (): React.ReactNode => {
     callback: (coordinates: ClickCoordinates, element: BioEntity | NewReaction | undefined) => void,
   ) => {
     return () => {
-      dispatch(closeContextMenu());
+      closeContextMenuFunction();
       return callback(
         {
           modelId,
@@ -61,55 +66,57 @@ export const ContextMenu = (): React.ReactNode => {
   };
 
   return (
-    <div
-      className={twMerge(
-        'absolute z-10 rounded-lg border border-[#DBD9D9] bg-white p-4',
-        isOpen ? '' : 'hidden',
-      )}
-      style={{
-        left: `${coordinates[FIRST_ARRAY_ELEMENT]}px`,
-        top: `${coordinates[SECOND_ARRAY_ELEMENT]}px`,
-      }}
-      data-testid="context-modal"
-    >
-      <button
+    <OutsideClickWrapper onOutsideClick={closeContextMenuFunction}>
+      <div
         className={twMerge(
-          'w-full cursor-pointer text-left text-xs font-normal',
-          !isUnitProtIdAvailable() ? 'cursor-not-allowed text-greyscale-700' : '',
+          'absolute z-10 rounded-lg border border-[#DBD9D9] bg-white p-4',
+          isOpen ? '' : 'hidden',
         )}
-        onClick={handleOpenMolArtClick}
-        type="button"
-        data-testid="open-molart"
-      >
-        Open MolArt ({getUnitProtId()})
-      </button>
-      <hr />
-      <button
-        className={twMerge('w-full cursor-pointer text-left text-xs font-normal')}
-        onClick={handleAddCommentClick}
-        type="button"
-        data-testid="add-comment"
+        style={{
+          left: `${coordinates[FIRST_ARRAY_ELEMENT]}px`,
+          top: `${coordinates[SECOND_ARRAY_ELEMENT]}px`,
+        }}
+        data-testid="context-modal"
       >
-        Add comment
-      </button>
-      {pluginContextMenu.length && <hr />}
-
-      {pluginContextMenu.map(contextMenuEntry => (
         <button
-          key={contextMenuEntry.id}
-          id={contextMenuEntry.id}
           className={twMerge(
-            'cursor-pointer text-xs font-normal',
-            contextMenuEntry.style,
-            !contextMenuEntry.enabled ? 'cursor-not-allowed text-greyscale-700' : '',
+            'w-full cursor-pointer text-left text-xs font-normal',
+            !isUnitProtIdAvailable() ? 'cursor-not-allowed text-greyscale-700' : '',
           )}
-          onClick={handleCallback(contextMenuEntry.callback)}
+          onClick={handleOpenMolArtClick}
           type="button"
-          data-testid={contextMenuEntry.id}
+          data-testid="open-molart"
         >
-          {contextMenuEntry.name}
+          Open MolArt ({getUnitProtId()})
         </button>
-      ))}
-    </div>
+        <hr />
+        <button
+          className={twMerge('w-full cursor-pointer text-left text-xs font-normal')}
+          onClick={handleAddCommentClick}
+          type="button"
+          data-testid="add-comment"
+        >
+          Add comment
+        </button>
+        {pluginContextMenu.length && <hr />}
+
+        {pluginContextMenu.map(contextMenuEntry => (
+          <button
+            key={contextMenuEntry.id}
+            id={contextMenuEntry.id}
+            className={twMerge(
+              'cursor-pointer text-xs font-normal',
+              contextMenuEntry.style,
+              !contextMenuEntry.enabled ? 'cursor-not-allowed text-greyscale-700' : '',
+            )}
+            onClick={handleCallback(contextMenuEntry.callback)}
+            type="button"
+            data-testid={contextMenuEntry.id}
+          >
+            {contextMenuEntry.name}
+          </button>
+        ))}
+      </div>
+    </OutsideClickWrapper>
   );
 };
diff --git a/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts b/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts
index 5bc52a7fd486077744fe048effab865d59c6639e..614d3dcf06a521ffb3fe170362e760b59905086b 100644
--- a/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants.ts
@@ -4,6 +4,11 @@ export const VECTOR_MAP_LAYER_TYPE = 'vectorMapLayer';
 
 export const COMPLEX_SBO_TERMS = ['SBO:0000253', 'SBO:0000297', 'SBO:0000289'];
 
+export const TEXT_CUTOFF_SCALE = 0.34;
+export const OUTLINE_CUTOFF_SCALE = 0.18;
+export const COMPLEX_CONTENTS_CUTOFF_SCALE = 0.215;
+export const REACTION_ELEMENT_CUTOFF_SCALE = 0.125;
+
 export const WHITE_COLOR: Color = {
   alpha: 255,
   rgb: 16777215,
@@ -20,27 +25,27 @@ export const TRANSPARENT_COLOR: Color = {
 };
 
 export const REACTION_ELEMENT_TYPES = {
-  OPERATOR: 'operator',
-  SQUARE: 'square',
-  LINE: 'line',
-  ARROW: 'arrow',
+  OPERATOR: 'OPERATOR',
+  SQUARE: 'SQUARE',
+  LINE: 'LINE',
+  ARROW: 'ARROW',
 };
 
 export const MAP_ELEMENT_TYPES = {
-  TEXT: 'text',
-  MODIFICATION: 'modification',
-  ACTIVITY_BORDER: 'activityBorder',
-  ENTITY: 'entity',
-  OVERLAY: 'overlay',
-  COMPARTMENT: 'compartment',
+  TEXT: 'TEXT',
+  MODIFICATION: 'MODIFICATION',
+  ACTIVITY_BORDER: 'ACTIVITY_BORDER',
+  ENTITY: 'ENTITY',
+  OVERLAY: 'OVERLAY',
+  COMPARTMENT: 'COMPARTMENT',
 };
 
 export const LAYER_ELEMENT_TYPES = {
-  TEXT: 'text',
-  OVAL: 'oval',
-  RECT: 'rect',
-  LINE: 'line',
-  ARROW: 'arrow',
+  TEXT: 'TEXT',
+  OVAL: 'OVAL',
+  RECT: 'RECT',
+  LINE: 'LINE',
+  ARROW: 'ARROW',
 };
 
 export const COMPARTMENT_SQUARE_POINTS: Array<ShapeRelAbs | ShapeRelAbsBezierPoint> = [
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
index 3a100b052ddf2783c7792c7033589efc069606f5..553893c422c52f5565777cfc798ec7b4d5d8c0cf 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/BaseMultiPolygon.ts
@@ -14,8 +14,11 @@ import { rgbToHex } from '@/components/Map/MapViewer/MapViewerVector/utils/shape
 import getTextCoords from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/text/getTextCoords';
 import { Color } from '@/types/models';
 import {
+  COMPLEX_CONTENTS_CUTOFF_SCALE,
   COMPLEX_SBO_TERMS,
   MAP_ELEMENT_TYPES,
+  OUTLINE_CUTOFF_SCALE,
+  TEXT_CUTOFF_SCALE,
 } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
 import VectorSource from 'ol/source/Vector';
 import MapBackgroundsEnum from '@/redux/map/map.enums';
@@ -259,12 +262,16 @@ export default abstract class BaseMultiPolygon {
     let cover = false;
     let largestExtent: Extent | null;
 
-    if (this.complexId && !COMPLEX_SBO_TERMS.includes(this.sboTerm) && scale < 0.215) {
+    if (
+      this.complexId &&
+      !COMPLEX_SBO_TERMS.includes(this.sboTerm) &&
+      scale < COMPLEX_CONTENTS_CUTOFF_SCALE
+    ) {
       return [];
     }
 
     let hide = false;
-    if (this.mapBackgroundType === MapBackgroundsEnum.SEMANTIC && scale < 0.34) {
+    if (this.mapBackgroundType === MapBackgroundsEnum.SEMANTIC && scale < TEXT_CUTOFF_SCALE) {
       const semanticViewData = handleSemanticView({
         vectorSource: this.vectorSource,
         feature,
@@ -311,18 +318,21 @@ export default abstract class BaseMultiPolygon {
         return;
       }
 
-      if ([MAP_ELEMENT_TYPES.MODIFICATION, MAP_ELEMENT_TYPES.TEXT].includes(type) && scale < 0.34) {
+      if (
+        [MAP_ELEMENT_TYPES.MODIFICATION, MAP_ELEMENT_TYPES.TEXT].includes(type) &&
+        scale < TEXT_CUTOFF_SCALE
+      ) {
         return;
       }
 
       const textStyle = style.getText();
-      if (type === 'text' && textStyle) {
+      if (type === MAP_ELEMENT_TYPES.TEXT && textStyle) {
         textStyle.setScale(scale);
       }
       if (strokeStyle) {
         if (
           !this.overlaysVisible &&
-          scale < 0.18 &&
+          scale < OUTLINE_CUTOFF_SCALE &&
           !COMPLEX_SBO_TERMS.includes(this.sboTerm) &&
           this.type !== MAP_ELEMENT_TYPES.COMPARTMENT
         ) {
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Compartment.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Compartment.ts
index 8906e75dab9219c5aa4b370254c564f5dc3eedc5..987fd2cee18029603d330e2f7512ac7069554ba5 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Compartment.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/Compartment.ts
@@ -97,7 +97,7 @@ export default abstract class Compartment extends BaseMultiPolygon {
     mapSize,
   }: CompartmentProps) {
     super({
-      type: 'COMPARTMENT',
+      type: MAP_ELEMENT_TYPES.COMPARTMENT,
       id,
       complexId,
       compartmentId,
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.ts
index e758a681ec3addb34553e58e79ed8085b72aa6e2..2850176f0d50cf9617d7fa0ea50bd33aa6732b57 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/CompartmentPathway.ts
@@ -87,7 +87,7 @@ export default class CompartmentPathway extends BaseMultiPolygon {
     mapSize,
   }: CompartmentPathwayProps) {
     super({
-      type: 'COMPARTMENT',
+      type: MAP_ELEMENT_TYPES.COMPARTMENT,
       id,
       complexId,
       compartmentId,
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
index 224921672e47f9a81753cd1a80ee4e679003f237..781903923472b930d15b88020345424fadebd913 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/handleSemanticView.ts
@@ -4,7 +4,10 @@ import findLargestExtent from '@/components/Map/MapViewer/MapViewerVector/utils/
 import Feature from 'ol/Feature';
 import VectorSource from 'ol/source/Vector';
 import { Extent } from 'ol/extent';
-import { COMPLEX_SBO_TERMS } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
+import {
+  COMPLEX_SBO_TERMS,
+  MAP_ELEMENT_TYPES,
+} from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
 import isFeatureInCompartment from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/elements/isFeatureInCompartment';
 
 export default function handleSemanticView({
@@ -34,7 +37,7 @@ export default function handleSemanticView({
   let largestExtent: Extent | null = null;
   if (
     getMapExtent instanceof Function &&
-    (type === 'COMPARTMENT' || COMPLEX_SBO_TERMS.includes(sboTerm))
+    (type === MAP_ELEMENT_TYPES.COMPARTMENT || COMPLEX_SBO_TERMS.includes(sboTerm))
   ) {
     const mapExtent = getMapExtent(resolution);
     const featureExtent = feature.getGeometry()?.getExtent();
@@ -49,7 +52,7 @@ export default function handleSemanticView({
         let remainingExtents = [featureExtent];
         vectorSource.forEachFeatureIntersectingExtent(featureExtent, intersectingFeature => {
           if (
-            intersectingFeature.get('type') === 'COMPARTMENT' &&
+            intersectingFeature.get('type') === MAP_ELEMENT_TYPES.COMPARTMENT &&
             intersectingFeature.get('zIndex') > feature.get('zIndex') &&
             intersectingFeature.get('filled') &&
             !isFeatureInCompartment(+featureId, vectorSource, intersectingFeature)
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts
index 29f17e00af39fb20d135bf1784b5abeb03a83737..0b8d6403d8ebc05700fe6e32a8ce71e988000aaf 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/layer/Layer.ts
@@ -21,6 +21,7 @@ import Style from 'ol/style/Style';
 import { ArrowTypeDict, LineTypeDict } from '@/redux/shapes/shapes.types';
 import {
   LAYER_ELEMENT_TYPES,
+  REACTION_ELEMENT_CUTOFF_SCALE,
   TRANSPARENT_COLOR,
 } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
 import getScaledElementStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/style/getScaledElementStyle';
@@ -305,7 +306,7 @@ export default class Layer {
     let strokeStyle: Stroke | undefined;
     const type = feature.get('elementType');
 
-    if (type === LAYER_ELEMENT_TYPES.ARROW && scale <= 0.08) {
+    if (type === LAYER_ELEMENT_TYPES.ARROW && scale <= REACTION_ELEMENT_CUTOFF_SCALE) {
       return [];
     }
 
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
index e6e2de63ab686dec013cd8d7ee202be207771c05..ccefcd64da957e5a1ffef93fcb9398108eb54017 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction.ts
@@ -7,7 +7,9 @@ import getStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/st
 import Polygon from 'ol/geom/Polygon';
 import Style from 'ol/style/Style';
 import {
+  REACTION_ELEMENT_CUTOFF_SCALE,
   REACTION_ELEMENT_TYPES,
+  TEXT_CUTOFF_SCALE,
   WHITE_COLOR,
 } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
 import { FeatureLike } from 'ol/Feature';
@@ -372,10 +374,7 @@ export default class Reaction {
     const type = feature.get('elementType');
     let strokeStyle: Stroke | undefined;
 
-    if (type === REACTION_ELEMENT_TYPES.OPERATOR && scale < 0.34) {
-      return [];
-    }
-    if (type === REACTION_ELEMENT_TYPES.ARROW && scale <= 0.125) {
+    if (type === REACTION_ELEMENT_TYPES.OPERATOR && scale < TEXT_CUTOFF_SCALE) {
       return [];
     }
 
@@ -406,7 +405,7 @@ export default class Reaction {
     const scale = this.minResolution / resolution;
     let strokeStyle: Stroke | undefined;
 
-    if (scale <= 0.125) {
+    if (scale <= REACTION_ELEMENT_CUTOFF_SCALE) {
       return [];
     }
 
diff --git a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/text/Text.ts b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/text/Text.ts
index 6d84b083bd1cfda2dd3fc15f5ebcdc0a4d417070..27b8ec6f59260848cfeb6581ee1c8e91b99f61d8 100644
--- a/src/components/Map/MapViewer/MapViewerVector/utils/shapes/text/Text.ts
+++ b/src/components/Map/MapViewer/MapViewerVector/utils/shapes/text/Text.ts
@@ -13,6 +13,7 @@ import { MapInstance } from '@/types/map';
 import getTextCoords from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/text/getTextCoords';
 import getTextStyle from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/text/getTextStyle';
 import { Color } from '@/types/models';
+import { TEXT_CUTOFF_SCALE } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
 
 export interface TextProps {
   x: number;
@@ -101,15 +102,10 @@ export default class Text {
     if (getTextScale instanceof Function) {
       textScale = getTextScale(resolution);
     }
-
-    if (this.style.getText()) {
-      if (this.fontSize * textScale > 4) {
-        this.style.getText()?.setScale(textScale);
-        this.style.getText()?.setText(this.text);
-      } else {
-        this.style.getText()?.setText(undefined);
-      }
+    if (textScale < TEXT_CUTOFF_SCALE) {
+      return undefined;
     }
+    this.style.getText()?.setScale(textScale);
     return this.style;
   }
 }
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapView.ts b/src/components/Map/MapViewer/utils/config/useOlMapView.ts
index cdf5b8f5c668c8336b7e332d854d2c72c9aa874e..d76947fdfa250784062178211202a1f7a3fff1d8 100644
--- a/src/components/Map/MapViewer/utils/config/useOlMapView.ts
+++ b/src/components/Map/MapViewer/utils/config/useOlMapView.ts
@@ -1,5 +1,5 @@
 /* eslint-disable no-magic-numbers */
-import { OPTIONS, ZOOM_RESCALING_FACTOR } from '@/constants/map';
+import { DEFAULT_EXTENT_PADDING, OPTIONS, ZOOM_RESCALING_FACTOR } from '@/constants/map';
 import { mapDataInitialPositionSelector, mapDataSizeSelector } from '@/redux/map/map.selectors';
 import { MapInstance, Point } from '@/types/map';
 import { usePointToProjection } from '@/utils/map/usePointToProjection';
@@ -34,13 +34,13 @@ export const useOlMapView = ({ mapInstance }: UseOlMapViewInput): MapConfig['vie
       heightPadding = mapSize.width / mapInstanceWidthToHeightRatio - mapSize.height;
     }
     const topLeftPoint: Point = {
-      x: mapSize.width + widthPadding / 2,
-      y: mapSize.height + heightPadding / 2,
+      x: mapSize.width + widthPadding / 2 + DEFAULT_EXTENT_PADDING,
+      y: mapSize.height + heightPadding / 2 + DEFAULT_EXTENT_PADDING,
     };
 
     const bottomRightPoint: Point = {
-      x: -widthPadding / 2,
-      y: -heightPadding / 2,
+      x: -widthPadding / 2 - DEFAULT_EXTENT_PADDING,
+      y: -heightPadding / 2 - DEFAULT_EXTENT_PADDING,
     };
 
     return boundingExtent([topLeftPoint, bottomRightPoint].map(pointToProjection));
diff --git a/src/constants/map.ts b/src/constants/map.ts
index d7efb594341aee93bf286ec885e543fb87036e8e..c995fdad5c637c292fc4162dd24dc6ac07e1021d 100644
--- a/src/constants/map.ts
+++ b/src/constants/map.ts
@@ -11,7 +11,7 @@ export const DEFAULT_CENTER_Y = 0;
 // eslint-disable-next-line no-magic-numbers
 export const LATLNG_FALLBACK: LatLng = [0, 0];
 export const EXTENT_PADDING_MULTIPLICATOR = 1;
-
+export const DEFAULT_EXTENT_PADDING = 20;
 export const ZOOM_RESCALING_FACTOR = 1;
 
 export const DEFAULT_CENTER_POINT: Point = {
diff --git a/src/shared/OutsideClickWrapper/OutsideClickWrapper.component.test.tsx b/src/shared/OutsideClickWrapper/OutsideClickWrapper.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..9070b6bb1b12d609e8e447e98d93c92611de3ad3
--- /dev/null
+++ b/src/shared/OutsideClickWrapper/OutsideClickWrapper.component.test.tsx
@@ -0,0 +1,40 @@
+/* eslint-disable no-magic-numbers */
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react';
+import { OutsideClickWrapper } from '.';
+
+describe('OutsideClickWrapper', () => {
+  it('should call onOutsideClick when click outside the component', () => {
+    const handleOutsideClick = jest.fn();
+    const { getByText } = render(
+      <OutsideClickWrapper onOutsideClick={handleOutsideClick}>
+        <div>Inner element</div>
+      </OutsideClickWrapper>,
+    );
+
+    const innerElement = getByText('Inner element');
+
+    fireEvent.mouseDown(document.body);
+
+    expect(handleOutsideClick).toHaveBeenCalledTimes(1);
+
+    fireEvent.mouseDown(innerElement);
+
+    expect(handleOutsideClick).toHaveBeenCalledTimes(1);
+  });
+
+  it('should not call onOutsideClick when click inside the component', () => {
+    const handleOutsideClick = jest.fn();
+    const { getByText } = render(
+      <OutsideClickWrapper onOutsideClick={handleOutsideClick}>
+        <div>Inner element</div>
+      </OutsideClickWrapper>,
+    );
+
+    const innerElement = getByText('Inner element');
+
+    fireEvent.mouseDown(innerElement);
+
+    expect(handleOutsideClick).not.toHaveBeenCalled();
+  });
+});
diff --git a/src/shared/OutsideClickWrapper/OutsideClickWrapper.component.tsx b/src/shared/OutsideClickWrapper/OutsideClickWrapper.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..48c15e1fb985e3c885f9ccffbd92f797ada2211d
--- /dev/null
+++ b/src/shared/OutsideClickWrapper/OutsideClickWrapper.component.tsx
@@ -0,0 +1,29 @@
+import React, { useEffect, useRef, ReactNode } from 'react';
+
+interface OutsideClickHandlerProps {
+  onOutsideClick: () => void;
+  children: ReactNode;
+}
+
+export const OutsideClickWrapper: React.FC<OutsideClickHandlerProps> = ({
+  onOutsideClick,
+  children,
+}) => {
+  const ref = useRef<HTMLDivElement>(null);
+
+  useEffect(() => {
+    const handleClickOutside = (event: MouseEvent): void => {
+      if (ref.current && !ref.current.contains(event.target as Node)) {
+        onOutsideClick();
+      }
+    };
+
+    document.addEventListener('mousedown', handleClickOutside);
+
+    return () => {
+      document.removeEventListener('mousedown', handleClickOutside);
+    };
+  }, [onOutsideClick]);
+
+  return <div ref={ref}>{children}</div>;
+};
diff --git a/src/shared/OutsideClickWrapper/index.tsx b/src/shared/OutsideClickWrapper/index.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..1535d4cf27cd460f7eccc7724fe653d3e5a1e2b1
--- /dev/null
+++ b/src/shared/OutsideClickWrapper/index.tsx
@@ -0,0 +1 @@
+export { OutsideClickWrapper } from './OutsideClickWrapper.component';