diff --git a/docs/plugins.md b/docs/plugins.md
new file mode 100644
index 0000000000000000000000000000000000000000..58af6267784516957b43981226f5e22bbd95820e
--- /dev/null
+++ b/docs/plugins.md
@@ -0,0 +1,82 @@
+# Plugin Integration with Minerva
+
+To seamlessly integrate your plugin with Minerva, follow these guidelines to ensure smooth registration, HTML structure creation, and interaction with Minerva.
+
+## Registering plugin with Minerva
+
+Your plugin should utilize the `window.minerva.plugins.registerPlugin` method for plugin registration. When the plugin is initialized, this method should be called inside plugin initialization method. The function `window.minerva.plugins.registerPlugin` takes an object as an argument:
+
+```ts
+{
+  pluginName: string;
+  pluginVersion: string;
+  pluginUrl: string;
+}
+```
+
+##### Usage example:
+
+```javascript
+window.minerva.plugins.registerPlugin({
+  pluginName: 'Your Plugin Name',
+  pluginVersion: '1.8.3',
+  pluginUrl: 'https://example.com/plugins/plugin.js',
+});
+```
+
+## Creating Plugin's HTML Structure
+
+The `window.minerva.plugins.registerPlugin` method returns object with `element` property which is a DOM element, allowing your plugin to append its HTML content to the DOM. Use this element to create and modify the HTML structure of your plugin.
+
+```
+// Plugin registration
+const { element } = window.minerva.plugins.registerPlugin({
+  pluginName: "Your Plugin Name",
+  pluginVersion: "1.0.0",
+  pluginUrl: "your-plugin-url",
+});
+
+// Modify plugin's HTML structure
+const yourContent = document.createElement('div');
+yourContent.textContent = "Your Plugin Content";
+element.appendChild(yourContent);
+```
+
+## Interacting with Minerva
+
+All interactions with Minerva should happen through the `window.minerva` object. This object includes:
+
+- configuration: includes information about available types of elements, reactions, miriam types, configuration options, map types and so on
+- methods will be added in the future
+
+## Example of plugin code before bundling:
+
+```javascript
+require('../css/styles.css');
+const $ = require('jquery');
+
+let pluginContainer;
+
+const createStructure = () => {
+  $(
+    `<div class="flex flex-col items-center p-2.5">
+      <h1 class="text-lg">My plugin ${minerva.configuration.overlayTypes[0].name}</h1>
+      <input class="mt-2.5 p-2.5 rounded-s font-semibold outline-none border border-[#cacaca] bg-[#f7f7f8]" value="https://minerva-dev.lcsb.uni.lu/minerva">
+    </div>`,
+  ).appendTo(pluginContainer);
+};
+
+function initPlugin() {
+  const { element } = window.minerva.plugins.registerPlugin({
+    pluginName: 'perfect-plugin',
+    pluginVersion: '9.9.9',
+    pluginUrl: 'https://example.com/plugins/perfect-plugin.js',
+  });
+
+  pluginContainer = element;
+
+  createStructure();
+}
+
+initPlugin();
+```
diff --git a/index.d.ts b/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..248f6f8ecb2d8aa13e21e2859fbfafacc263eba2
--- /dev/null
+++ b/index.d.ts
@@ -0,0 +1,27 @@
+import { MinervaConfiguration } from '@/services/pluginsManager/pluginsManager';
+
+type Plugin = {
+  pluginName: string;
+  pluginVersion: string;
+  pluginUrl: string;
+};
+
+type RegisterPlugin = ({ pluginName, pluginVersion, pluginUrl }: Plugin) => {
+  element: HTMLDivElement;
+};
+
+type HashPlugin = {
+  pluginUrl: string;
+  pluginScript: string;
+};
+
+declare global {
+  interface Window {
+    minerva: {
+      configuration?: MinervaConfiguration;
+      plugins: {
+        registerPlugin: RegisterPlugin;
+      };
+    };
+  }
+}
diff --git a/package-lock.json b/package-lock.json
index fda23e3ba417c3a63f180521727bc071a4ac8ff4..f03034da82f849c388f0ea38401273ee54e4d1ca 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
         "autoprefixer": "10.4.15",
         "axios": "^1.5.1",
         "axios-hooks": "^5.0.0",
+        "crypto-js": "^4.2.0",
         "downshift": "^8.2.3",
         "eslint-config-next": "13.4.19",
         "molart": "github:davidhoksza/MolArt",
@@ -28,6 +29,8 @@
         "query-string": "7.1.3",
         "react": "18.2.0",
         "react-accessible-accordion": "^5.0.0",
+        "react-dnd": "^16.0.1",
+        "react-dnd-html5-backend": "^16.0.1",
         "react-dom": "18.2.0",
         "react-dropzone": "^14.2.3",
         "react-redux": "^8.1.2",
@@ -42,6 +45,8 @@
         "@commitlint/config-conventional": "^17.7.0",
         "@testing-library/jest-dom": "^6.1.3",
         "@testing-library/react": "^14.0.0",
+        "@testing-library/user-event": "^14.5.2",
+        "@types/crypto-js": "^4.2.2",
         "@types/jest": "^29.5.5",
         "@types/react-redux": "^7.1.26",
         "@types/redux-mock-store": "^1.0.6",
@@ -1959,6 +1964,21 @@
         "url": "https://opencollective.com/unts"
       }
     },
+    "node_modules/@react-dnd/asap": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz",
+      "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A=="
+    },
+    "node_modules/@react-dnd/invariant": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz",
+      "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw=="
+    },
+    "node_modules/@react-dnd/shallowequal": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
+      "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA=="
+    },
     "node_modules/@reduxjs/toolkit": {
       "version": "1.9.7",
       "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz",
@@ -2165,6 +2185,19 @@
         "react-dom": "^18.0.0"
       }
     },
+    "node_modules/@testing-library/user-event": {
+      "version": "14.5.2",
+      "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz",
+      "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=12",
+        "npm": ">=6"
+      },
+      "peerDependencies": {
+        "@testing-library/dom": ">=7.21.4"
+      }
+    },
     "node_modules/@tootallnate/once": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@@ -2245,6 +2278,12 @@
         "@babel/types": "^7.20.7"
       }
     },
+    "node_modules/@types/crypto-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz",
+      "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==",
+      "dev": true
+    },
     "node_modules/@types/downloadjs": {
       "version": "1.4.6",
       "resolved": "https://registry.npmjs.org/@types/downloadjs/-/downloadjs-1.4.6.tgz",
@@ -4340,6 +4379,11 @@
         "node": ">= 8"
       }
     },
+    "node_modules/crypto-js": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+      "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
+    },
     "node_modules/css.escape": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
@@ -4929,6 +4973,16 @@
       "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
       "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
     },
+    "node_modules/dnd-core": {
+      "version": "16.0.1",
+      "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz",
+      "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==",
+      "dependencies": {
+        "@react-dnd/asap": "^5.0.1",
+        "@react-dnd/invariant": "^4.0.1",
+        "redux": "^4.2.0"
+      }
+    },
     "node_modules/doctrine": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
@@ -11559,6 +11613,43 @@
         "react-dom": "^16.3.3 || ^17.0.0 || ^18.0.0"
       }
     },
+    "node_modules/react-dnd": {
+      "version": "16.0.1",
+      "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz",
+      "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==",
+      "dependencies": {
+        "@react-dnd/invariant": "^4.0.1",
+        "@react-dnd/shallowequal": "^4.0.1",
+        "dnd-core": "^16.0.1",
+        "fast-deep-equal": "^3.1.3",
+        "hoist-non-react-statics": "^3.3.2"
+      },
+      "peerDependencies": {
+        "@types/hoist-non-react-statics": ">= 3.3.1",
+        "@types/node": ">= 12",
+        "@types/react": ">= 16",
+        "react": ">= 16.14"
+      },
+      "peerDependenciesMeta": {
+        "@types/hoist-non-react-statics": {
+          "optional": true
+        },
+        "@types/node": {
+          "optional": true
+        },
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-dnd-html5-backend": {
+      "version": "16.0.1",
+      "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz",
+      "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==",
+      "dependencies": {
+        "dnd-core": "^16.0.1"
+      }
+    },
     "node_modules/react-dom": {
       "version": "18.2.0",
       "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
@@ -15325,6 +15416,21 @@
       "integrity": "sha512-Zwq5OCzuwJC2jwqmpEQt7Ds1DTi6BWSwoGkbb1n9pO3hzb35BoJELx7c0T23iDkBGkh2e7tvOtjF3tr3OaQHDQ==",
       "dev": true
     },
+    "@react-dnd/asap": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz",
+      "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A=="
+    },
+    "@react-dnd/invariant": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz",
+      "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw=="
+    },
+    "@react-dnd/shallowequal": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
+      "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA=="
+    },
     "@reduxjs/toolkit": {
       "version": "1.9.7",
       "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz",
@@ -15461,6 +15567,13 @@
         "@types/react-dom": "^18.0.0"
       }
     },
+    "@testing-library/user-event": {
+      "version": "14.5.2",
+      "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz",
+      "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==",
+      "dev": true,
+      "requires": {}
+    },
     "@tootallnate/once": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@@ -15538,6 +15651,12 @@
         "@babel/types": "^7.20.7"
       }
     },
+    "@types/crypto-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz",
+      "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==",
+      "dev": true
+    },
     "@types/downloadjs": {
       "version": "1.4.6",
       "resolved": "https://registry.npmjs.org/@types/downloadjs/-/downloadjs-1.4.6.tgz",
@@ -17064,6 +17183,11 @@
         "which": "^2.0.1"
       }
     },
+    "crypto-js": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+      "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
+    },
     "css.escape": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
@@ -17524,6 +17648,16 @@
       "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
       "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
     },
+    "dnd-core": {
+      "version": "16.0.1",
+      "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz",
+      "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==",
+      "requires": {
+        "@react-dnd/asap": "^5.0.1",
+        "@react-dnd/invariant": "^4.0.1",
+        "redux": "^4.2.0"
+      }
+    },
     "doctrine": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
@@ -22205,6 +22339,26 @@
       "integrity": "sha512-MT2obYpTgLIIfPr9d7hEyvPB5rg8uJcHpgA83JSRlEUHvzH48+8HJPvzSs+nM+XprTugDgLfhozO5qyJpBvYRQ==",
       "requires": {}
     },
+    "react-dnd": {
+      "version": "16.0.1",
+      "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz",
+      "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==",
+      "requires": {
+        "@react-dnd/invariant": "^4.0.1",
+        "@react-dnd/shallowequal": "^4.0.1",
+        "dnd-core": "^16.0.1",
+        "fast-deep-equal": "^3.1.3",
+        "hoist-non-react-statics": "^3.3.2"
+      }
+    },
+    "react-dnd-html5-backend": {
+      "version": "16.0.1",
+      "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz",
+      "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==",
+      "requires": {
+        "dnd-core": "^16.0.1"
+      }
+    },
     "react-dom": {
       "version": "18.2.0",
       "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
diff --git a/package.json b/package.json
index e45e31b66caee289777e05e7e30301a7a8592d93..730be9f5d6988dabee2e69c54847d7ce860defb5 100644
--- a/package.json
+++ b/package.json
@@ -14,9 +14,9 @@
     "check-types": "tsc --pretty --noEmit",
     "prepare": "husky install",
     "postinstall": "husky install",
-    "test": "jest --config ./jest.config.ts --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|color-space|color-rgba|color-parse|.*\\.mjs$))'",
-    "test:watch": "jest --watch --config ./jest.config.ts --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|color-space|color-rgba|color-parse|.*\\.mjs$))'",
-    "test:ci": "jest --config ./jest.config.ts --collectCoverage --coverageDirectory=\"./coverage\" --ci --reporters=default --reporters=jest-junit --watchAll=false --passWithNoTests --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|color-space|color-rgba|color-parse|.*\\.mjs$))'",
+    "test": "jest --config ./jest.config.ts --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|color-space|color-rgba|color-parse|.*\\.mjs$|@react-dnd|@babel|redux|react-dnd|dnd-core|react-dnd-html5-backend))'",
+    "test:watch": "jest --watch --config ./jest.config.ts --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|color-space|color-rgba|color-parse|.*\\.mjs$|@react-dnd|@babel|redux|react-dnd|dnd-core|react-dnd-html5-backend))'",
+    "test:ci": "jest --config ./jest.config.ts --collectCoverage --coverageDirectory=\"./coverage\" --ci --reporters=default --reporters=jest-junit --watchAll=false --passWithNoTests --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|color-space|color-rgba|color-parse|.*\\.mjs$|@react-dnd|@babel|redux|react-dnd|dnd-core|react-dnd-html5-backend))'",
     "test:coverage": "jest --watchAll --coverage --config ./jest.config.ts --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|.*\\.mjs$))'",
     "test:coveragee": "jest --coverage --transformIgnorePatterns 'node_modules/(?!(ol|geotiff|quick-lru|.*\\.mjs$))'",
     "coverage": "open ./coverage/lcov-report/index.html",
@@ -33,6 +33,7 @@
     "autoprefixer": "10.4.15",
     "axios": "^1.5.1",
     "axios-hooks": "^5.0.0",
+    "crypto-js": "^4.2.0",
     "downshift": "^8.2.3",
     "eslint-config-next": "13.4.19",
     "molart": "github:davidhoksza/MolArt",
@@ -42,6 +43,8 @@
     "query-string": "7.1.3",
     "react": "18.2.0",
     "react-accessible-accordion": "^5.0.0",
+    "react-dnd": "^16.0.1",
+    "react-dnd-html5-backend": "^16.0.1",
     "react-dom": "18.2.0",
     "react-dropzone": "^14.2.3",
     "react-redux": "^8.1.2",
@@ -56,6 +59,8 @@
     "@commitlint/config-conventional": "^17.7.0",
     "@testing-library/jest-dom": "^6.1.3",
     "@testing-library/react": "^14.0.0",
+    "@types/crypto-js": "^4.2.2",
+    "@testing-library/user-event": "^14.5.2",
     "@types/jest": "^29.5.5",
     "@types/react-redux": "^7.1.26",
     "@types/redux-mock-store": "^1.0.6",
diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..f0934d79f6f54d7ea9008e43f5e84ba7f5faac04
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx
@@ -0,0 +1,159 @@
+import { render, screen, fireEvent } from '@testing-library/react';
+import { StoreType } from '@/redux/store';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { overlayFixture } from '@/models/fixtures/overlaysFixture';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { apiPath } from '@/redux/apiPath';
+import { HttpStatusCode } from 'axios';
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { act } from 'react-dom/test-utils';
+import { OVERLAYS_INITIAL_STATE_MOCK } from '@/redux/overlays/overlays.mock';
+import { Modal } from '../Modal.component';
+
+const mockedAxiosClient = mockNetworkResponse();
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <Modal />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('EditOverlayModal - component', () => {
+  it('should render modal with correct data', () => {
+    renderComponent({
+      modal: {
+        isOpen: true,
+        modalTitle: overlayFixture.name,
+        modalName: 'edit-overlay',
+        editOverlayState: overlayFixture,
+        molArtState: {},
+        overviewImagesState: {},
+      },
+    });
+
+    expect(screen.getByLabelText('Name')).toBeVisible();
+    expect(screen.getByLabelText('Description')).toBeVisible();
+    expect(screen.getByTestId('overlay-name')).toHaveValue(overlayFixture.name);
+    expect(screen.getByTestId('overlay-description')).toHaveValue(overlayFixture.description);
+  });
+  it('should handle input change correctly', () => {
+    renderComponent({
+      modal: {
+        isOpen: true,
+        modalTitle: overlayFixture.name,
+        modalName: 'edit-overlay',
+        editOverlayState: overlayFixture,
+        molArtState: {},
+        overviewImagesState: {},
+      },
+    });
+
+    const overlayNameInput: HTMLInputElement = screen.getByTestId('overlay-name');
+    const overlayDescriptionInput: HTMLTextAreaElement = screen.getByTestId('overlay-description');
+
+    fireEvent.change(overlayNameInput, { target: { value: 'Test name' } });
+    fireEvent.change(overlayDescriptionInput, { target: { value: 'Descripiton' } });
+
+    expect(overlayNameInput.value).toBe('Test name');
+    expect(overlayDescriptionInput.value).toBe('Descripiton');
+  });
+  it('should handle remove user overlay', async () => {
+    const { store } = renderComponent({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      modal: {
+        isOpen: true,
+        modalTitle: overlayFixture.name,
+        modalName: 'edit-overlay',
+        editOverlayState: overlayFixture,
+        molArtState: {},
+        overviewImagesState: {},
+      },
+      overlays: OVERLAYS_INITIAL_STATE_MOCK,
+    });
+    mockedAxiosClient
+      .onDelete(apiPath.removeOverlay(overlayFixture.idObject))
+      .reply(HttpStatusCode.Ok, {});
+
+    const removeButton = screen.getByTestId('remove-button');
+    expect(removeButton).toBeVisible();
+    await act(() => {
+      removeButton.click();
+    });
+
+    const { loading } = store.getState().overlays.removeOverlay;
+    expect(loading).toBe('succeeded');
+    expect(removeButton).not.toBeVisible();
+  });
+  it('should handle save edited user overlay', async () => {
+    const { store } = renderComponent({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      modal: {
+        isOpen: true,
+        modalTitle: overlayFixture.name,
+        modalName: 'edit-overlay',
+        editOverlayState: overlayFixture,
+        molArtState: {},
+        overviewImagesState: {},
+      },
+      overlays: OVERLAYS_INITIAL_STATE_MOCK,
+    });
+    mockedAxiosClient
+      .onPatch(apiPath.updateOverlay(overlayFixture.idObject))
+      .reply(HttpStatusCode.Ok, overlayFixture);
+
+    const saveButton = screen.getByTestId('save-button');
+    expect(saveButton).toBeVisible();
+    await act(() => {
+      saveButton.click();
+    });
+
+    const { loading } = store.getState().overlays.updateOverlays;
+    expect(loading).toBe('succeeded');
+    expect(saveButton).not.toBeVisible();
+  });
+
+  it('should handle cancel edit user overlay', async () => {
+    const { store } = renderComponent({
+      modal: {
+        isOpen: true,
+        modalTitle: overlayFixture.name,
+        modalName: 'edit-overlay',
+        editOverlayState: overlayFixture,
+        molArtState: {},
+        overviewImagesState: {},
+      },
+    });
+
+    const cancelButton = screen.getByTestId('cancel-button');
+    expect(cancelButton).toBeVisible();
+    await act(() => {
+      cancelButton.click();
+    });
+
+    const { isOpen } = store.getState().modal;
+    expect(isOpen).toBe(false);
+    expect(cancelButton).not.toBeVisible();
+  });
+});
diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.tsx b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..46091536090665c866f0df6e1c8be6e35590330a
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.tsx
@@ -0,0 +1,77 @@
+import { Button } from '@/shared/Button';
+import { Input } from '@/shared/Input';
+import { Textarea } from '@/shared/Textarea';
+import React from 'react';
+import { useEditOverlay } from './hooks/useEditOverlay';
+
+export const EditOverlayModal = (): React.ReactNode => {
+  const {
+    description,
+    name,
+    handleCancelEdit,
+    handleDescriptionChange,
+    handleNameChange,
+    handleRemoveOverlay,
+    handleSaveEditedOverlay,
+  } = useEditOverlay();
+
+  return (
+    <div className="w-full border border-t-[#E1E0E6] bg-white p-[24px]">
+      <form>
+        <label className="text-sm font-semibold" htmlFor="overlayName">
+          Name
+          <Input
+            type="text"
+            value={name}
+            onChange={handleNameChange}
+            name="overlayName"
+            id="overlayName"
+            className="mt-2.5 text-sm font-medium"
+            data-testid="overlay-name"
+          />
+        </label>
+        <label className="mt-5 block text-sm font-semibold" htmlFor="overlayDescription">
+          Description
+          <Textarea
+            rows={4}
+            value={description}
+            onChange={handleDescriptionChange}
+            name="overlayDescription"
+            id="overlayDescription"
+            className="mt-2.5 text-sm font-medium"
+            data-testid="overlay-description"
+          />
+        </label>
+        <div className="mt-10 flex items-center justify-between gap-5 text-center">
+          <Button
+            type="button"
+            variantStyles="ghost"
+            className="flex-1 justify-center"
+            onClick={handleCancelEdit}
+            data-testid="cancel-button"
+          >
+            Cancel
+          </Button>
+          <Button
+            type="button"
+            variantStyles="ghost"
+            className="flex-1 justify-center"
+            onClick={handleRemoveOverlay}
+            data-testid="remove-button"
+          >
+            Remove
+          </Button>
+
+          <Button
+            type="button"
+            className="flex-1 justify-center"
+            onClick={handleSaveEditedOverlay}
+            data-testid="save-button"
+          >
+            Save
+          </Button>
+        </div>
+      </form>
+    </div>
+  );
+};
diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8fcac18fbda172096b00d88362d8ec73476a098f
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts
@@ -0,0 +1,175 @@
+/* eslint-disable no-magic-numbers */
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { overlayFixture } from '@/models/fixtures/overlaysFixture';
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { renderHook } from '@testing-library/react';
+import { useEditOverlay } from './useEditOverlay';
+
+describe('useEditOverlay', () => {
+  it('should handle cancel edit overlay', () => {
+    const { Wrapper, store } = getReduxStoreWithActionsListener({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      modal: {
+        isOpen: true,
+        modalTitle: overlayFixture.name,
+        modalName: 'edit-overlay',
+        editOverlayState: overlayFixture,
+        molArtState: {},
+        overviewImagesState: {},
+      },
+    });
+
+    const {
+      result: {
+        current: { handleCancelEdit },
+      },
+    } = renderHook(() => useEditOverlay(), {
+      wrapper: Wrapper,
+    });
+
+    handleCancelEdit();
+
+    const actions = store.getActions();
+
+    expect(actions[0].type).toBe('modal/closeModal');
+  });
+
+  it('should handle handleRemoveOverlay if proper data is provided', () => {
+    const { Wrapper, store } = getReduxStoreWithActionsListener({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      modal: {
+        isOpen: true,
+        modalTitle: overlayFixture.name,
+        modalName: 'edit-overlay',
+        editOverlayState: overlayFixture,
+        molArtState: {},
+        overviewImagesState: {},
+      },
+    });
+
+    const {
+      result: {
+        current: { handleRemoveOverlay },
+      },
+    } = renderHook(() => useEditOverlay(), {
+      wrapper: Wrapper,
+    });
+
+    handleRemoveOverlay();
+
+    const actions = store.getActions();
+
+    expect(actions[0].type).toBe('overlays/removeOverlay/pending');
+
+    const { login, overlayId } = actions[0].meta.arg;
+    expect(login).toBe('test');
+    expect(overlayId).toBe(overlayFixture.idObject);
+  });
+  it('should not handle handleRemoveOverlay if proper data is not provided', () => {
+    const { Wrapper, store } = getReduxStoreWithActionsListener({
+      user: {
+        authenticated: true,
+        loading: 'failed',
+        error: DEFAULT_ERROR,
+        login: null,
+      },
+      modal: {
+        isOpen: true,
+        modalTitle: overlayFixture.name,
+        modalName: 'edit-overlay',
+        editOverlayState: overlayFixture,
+        molArtState: {},
+        overviewImagesState: {},
+      },
+    });
+
+    const {
+      result: {
+        current: { handleRemoveOverlay },
+      },
+    } = renderHook(() => useEditOverlay(), {
+      wrapper: Wrapper,
+    });
+
+    handleRemoveOverlay();
+
+    const actions = store.getActions();
+
+    expect(actions.length).toBe(0);
+  });
+  it('should handle handleSaveEditedOverlay if proper data is provided', () => {
+    const { Wrapper, store } = getReduxStoreWithActionsListener({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      modal: {
+        isOpen: true,
+        modalTitle: overlayFixture.name,
+        modalName: 'edit-overlay',
+        editOverlayState: overlayFixture,
+        molArtState: {},
+        overviewImagesState: {},
+      },
+    });
+
+    const {
+      result: {
+        current: { handleSaveEditedOverlay },
+      },
+    } = renderHook(() => useEditOverlay(), {
+      wrapper: Wrapper,
+    });
+
+    handleSaveEditedOverlay();
+
+    const actions = store.getActions();
+
+    expect(actions[0].type).toBe('overlays/updateOverlays/pending');
+    expect(actions[0].meta.arg).toEqual([overlayFixture]);
+  });
+  it('should not handle handleSaveEditedOverlay if proper data is not provided', () => {
+    const { Wrapper, store } = getReduxStoreWithActionsListener({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: null,
+      },
+      modal: {
+        isOpen: true,
+        modalTitle: overlayFixture.name,
+        modalName: 'edit-overlay',
+        editOverlayState: overlayFixture,
+        molArtState: {},
+        overviewImagesState: {},
+      },
+    });
+
+    const {
+      result: {
+        current: { handleSaveEditedOverlay },
+      },
+    } = renderHook(() => useEditOverlay(), {
+      wrapper: Wrapper,
+    });
+
+    handleSaveEditedOverlay();
+
+    const actions = store.getActions();
+
+    expect(actions.length).toBe(0);
+  });
+});
diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.ts b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.ts
new file mode 100644
index 0000000000000000000000000000000000000000..adb7778cddb6a3959480fe319a97ea888efca29a
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.ts
@@ -0,0 +1,100 @@
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { currentEditedOverlaySelector } from '@/redux/modal/modal.selector';
+import { closeModal } from '@/redux/modal/modal.slice';
+import {
+  getAllUserOverlaysByCreator,
+  removeOverlay,
+  updateOverlays,
+} from '@/redux/overlays/overlays.thunks';
+import { loginUserSelector } from '@/redux/user/user.selectors';
+import { MapOverlay } from '@/types/models';
+import { useState } from 'react';
+
+type UseEditOverlayReturn = {
+  name: string | undefined;
+  description: string | undefined;
+  handleCancelEdit: () => void;
+  handleRemoveOverlay: () => void;
+  handleSaveEditedOverlay: () => Promise<void>;
+  handleNameChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
+  handleDescriptionChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
+};
+
+type UpdatedOverlay = {
+  editedOverlay: MapOverlay;
+  overlayName: string;
+  overlayDescription: string;
+};
+
+export const useEditOverlay = (): UseEditOverlayReturn => {
+  const currentEditedOverlay = useAppSelector(currentEditedOverlaySelector);
+  const login = useAppSelector(loginUserSelector);
+  const dispatch = useAppDispatch();
+  const [name, setName] = useState(currentEditedOverlay?.name);
+  const [description, setDescription] = useState(currentEditedOverlay?.description);
+
+  const handleCancelEdit = (): void => {
+    dispatch(closeModal());
+  };
+
+  const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
+    setName(e.target.value);
+  };
+
+  const handleDescriptionChange = (e: React.ChangeEvent<HTMLTextAreaElement>): void => {
+    setDescription(e.target.value);
+  };
+
+  const handleRemoveOverlay = (): void => {
+    if (!login || !currentEditedOverlay) return;
+    dispatch(removeOverlay({ overlayId: currentEditedOverlay.idObject, login }));
+  };
+
+  const handleUpdateOverlay = async ({
+    editedOverlay,
+    overlayDescription,
+    overlayName,
+  }: UpdatedOverlay): Promise<void> => {
+    await dispatch(
+      updateOverlays([
+        {
+          ...editedOverlay,
+          name: overlayName,
+          description: overlayDescription,
+        },
+      ]),
+    );
+  };
+
+  const getUserOverlaysByCreator = async (creator: string): Promise<void> => {
+    await dispatch(getAllUserOverlaysByCreator(creator));
+  };
+
+  const handleCloseModal = (): void => {
+    dispatch(closeModal());
+  };
+
+  const handleSaveEditedOverlay = async (): Promise<void> => {
+    if (!currentEditedOverlay || !name || !description || !login) return;
+    await handleUpdateOverlay({
+      editedOverlay: currentEditedOverlay,
+      overlayDescription: description,
+      overlayName: name,
+    });
+
+    await getUserOverlaysByCreator(login);
+
+    handleCloseModal();
+  };
+
+  return {
+    handleCancelEdit,
+    handleRemoveOverlay,
+    handleSaveEditedOverlay,
+    handleNameChange,
+    handleDescriptionChange,
+    name,
+    description,
+  };
+};
diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/index.ts b/src/components/FunctionalArea/Modal/EditOverlayModal/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f847a6bd48e5dc648bfceb8a6865fb7316394d67
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/EditOverlayModal/index.ts
@@ -0,0 +1 @@
+export { EditOverlayModal } from './EditOverlayModal.component';
diff --git a/src/components/FunctionalArea/Modal/Modal.component.tsx b/src/components/FunctionalArea/Modal/Modal.component.tsx
index 00e22313022d97811b8f5de845cdd44eb0c87b93..e6500c336107407611d0c6b1646b67dccce12202 100644
--- a/src/components/FunctionalArea/Modal/Modal.component.tsx
+++ b/src/components/FunctionalArea/Modal/Modal.component.tsx
@@ -5,6 +5,7 @@ import { LoginModal } from './LoginModal';
 import { OverviewImagesModal } from './OverviewImagesModal';
 import { PublicationsModal } from './PublicationsModal';
 import { ModalLayout } from './ModalLayout';
+import { EditOverlayModal } from './EditOverlayModal';
 
 const MolArtModal = dynamic(
   () => import('./MolArtModal/MolArtModal.component').then(mod => mod.MolArtModal),
@@ -32,6 +33,11 @@ export const Modal = (): React.ReactNode => {
         </ModalLayout>
       )}
       {isOpen && modalName === 'publications' && <PublicationsModal />}
+      {isOpen && modalName === 'edit-overlay' && (
+        <ModalLayout>
+          <EditOverlayModal />
+        </ModalLayout>
+      )}
     </>
   );
 };
diff --git a/src/components/FunctionalArea/NavBar/NavBar.component.tsx b/src/components/FunctionalArea/NavBar/NavBar.component.tsx
index fbc5c000ee41e1dd810219d5d9cf181263fc02a7..41177e15ebdf3dccdb1d870f0e78acf59c98f71d 100644
--- a/src/components/FunctionalArea/NavBar/NavBar.component.tsx
+++ b/src/components/FunctionalArea/NavBar/NavBar.component.tsx
@@ -15,7 +15,7 @@ export const NavBar = (): JSX.Element => {
   };
 
   const openDrawerPlugins = (): void => {
-    dispatch(openDrawer('plugins'));
+    dispatch(openDrawer('available-plugins'));
   };
 
   const openDrawerExport = (): void => {
@@ -34,14 +34,14 @@ export const NavBar = (): JSX.Element => {
     <div className="flex min-h-full w-[88px] flex-col items-center justify-between bg-cultured py-8">
       <div data-testid="nav-buttons">
         <div className="mb-8 flex flex-col gap-[10px]">
-          <IconButton icon="info" onClick={openDrawerInfo} />
-          <IconButton icon="page" />
-          <IconButton icon="plugin" onClick={openDrawerPlugins} />
-          <IconButton icon="export" onClick={openDrawerExport} />
+          <IconButton icon="info" onClick={openDrawerInfo} title="Project info" />
+          <IconButton icon="page" title="API Doc" />
+          <IconButton icon="plugin" onClick={openDrawerPlugins} title="Available plugins" />
+          <IconButton icon="export" onClick={openDrawerExport} title="Export" />
         </div>
         <div className="flex flex-col gap-[10px]">
-          <IconButton icon="admin" onClick={openModalLogin} />
-          <IconButton icon="legend" onClick={openDrawerLegend} />
+          <IconButton icon="admin" onClick={openModalLogin} title="Login" />
+          <IconButton icon="legend" onClick={openDrawerLegend} title="Legend" />
         </div>
       </div>
 
diff --git a/src/components/FunctionalArea/TopBar/TopBar.component.tsx b/src/components/FunctionalArea/TopBar/TopBar.component.tsx
index 77c4eab9a59caabf1aebe8739f2679fe4966cab2..243ededa1542fd5ae10a6af2a9b65df8277932ca 100644
--- a/src/components/FunctionalArea/TopBar/TopBar.component.tsx
+++ b/src/components/FunctionalArea/TopBar/TopBar.component.tsx
@@ -20,10 +20,17 @@ export const TopBar = (): JSX.Element => {
       <div className="flex flex-row items-center">
         <UserAvatar />
         <SearchBar />
-        <Button icon="plus" isIcon isFrontIcon className="ml-8 mr-4" onClick={onSubmapsClick}>
+        <Button
+          icon="plus"
+          isIcon
+          isFrontIcon
+          className="ml-8 mr-4"
+          onClick={onSubmapsClick}
+          title="Submaps"
+        >
           Submaps
         </Button>
-        <Button icon="plus" isIcon isFrontIcon onClick={onOverlaysClick}>
+        <Button icon="plus" isIcon isFrontIcon onClick={onOverlaysClick} title="Overlays">
           Overlays
         </Button>
       </div>
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.test.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..06d70d35abe59da6cf05b3c3700d991746cc3db8
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.test.tsx
@@ -0,0 +1,53 @@
+import { PLUGINS_MOCK } from '@/models/mocks/pluginsMock';
+import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
+import { StoreType } from '@/redux/store';
+import { InitialStoreState } from '@/utils/testing/getReduxStoreActionsListener';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { render, screen } from '@testing-library/react';
+import { AvailablePluginsDrawer } from './AvailablePluginsDrawer.component';
+
+const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStore);
+  return (
+    render(
+      <Wrapper>
+        <AvailablePluginsDrawer />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('AvailablePluginsDrawer - component', () => {
+  describe('when always', () => {
+    it('should render drawer heading', () => {
+      renderComponent(INITIAL_STORE_STATE_MOCK);
+      const drawerTitle = screen.getByText('Available plugins');
+      expect(drawerTitle).toBeInTheDocument();
+    });
+
+    it('should render load plugin from url', () => {
+      renderComponent(INITIAL_STORE_STATE_MOCK);
+      const loadPluginFromUrlInput = screen.getByTestId('load-plugin-input-url');
+      expect(loadPluginFromUrlInput).toBeInTheDocument();
+    });
+
+    it.each(PLUGINS_MOCK)('should render render all public plugins', currentPlugin => {
+      renderComponent({
+        ...INITIAL_STORE_STATE_MOCK,
+        plugins: {
+          ...INITIAL_STORE_STATE_MOCK.plugins,
+          list: {
+            ...INITIAL_STORE_STATE_MOCK.plugins.list,
+            data: PLUGINS_MOCK,
+          },
+        },
+      });
+
+      const pluginLabel = screen.getByText(currentPlugin.name);
+      expect(pluginLabel).toBeInTheDocument();
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..80af258edc647d357865948e2e52a9dc333dcaba
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.tsx
@@ -0,0 +1,17 @@
+import { DrawerHeading } from '@/shared/DrawerHeading';
+import { LoadPluginFromUrl } from './LoadPluginFromUrl';
+import { PublicPlugins } from './PublicPlugins';
+import { PrivateActivePlugins } from './PrivateActivePlugins';
+
+export const AvailablePluginsDrawer = (): JSX.Element => {
+  return (
+    <div className="h-full max-h-full" data-testid="available-plugins-drawer">
+      <DrawerHeading title="Available plugins" />
+      <div className="flex flex-col gap-6 p-6">
+        <LoadPluginFromUrl />
+        <PrivateActivePlugins />
+        <PublicPlugins />
+      </div>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.test.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..ba8ea94c6ced7739c43e902ac3ac60020959b57a
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.test.tsx
@@ -0,0 +1,104 @@
+/* eslint-disable no-magic-numbers */
+import { FIRST_ARRAY_ELEMENT } from '@/constants/common';
+import { PLUGINS_MOCK } from '@/models/mocks/pluginsMock';
+import { render, screen } from '@testing-library/react';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { InitialStoreState } from '@/utils/testing/getReduxStoreActionsListener';
+import { StoreType } from '@/redux/store';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import MockAdapter from 'axios-mock-adapter';
+import axios, { HttpStatusCode } from 'axios';
+import { apiPath } from '@/redux/apiPath';
+import { act } from 'react-dom/test-utils';
+import { PLUGINS_INITIAL_STATE_LIST_MOCK } from '@/redux/plugins/plugins.mock';
+import { LoadPlugin, Props } from './LoadPlugin.component';
+
+const mockedAxiosApiClient = mockNetworkResponse();
+const mockedAxiosClient = new MockAdapter(axios);
+
+const renderComponent = (
+  { plugin }: Props,
+  initialStore?: InitialStoreState,
+): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStore);
+  return (
+    render(
+      <Wrapper>
+        <LoadPlugin plugin={plugin} />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('LoadPlugin - component', () => {
+  describe('when always', () => {
+    const plugin = PLUGINS_MOCK[FIRST_ARRAY_ELEMENT];
+
+    it('renders plugin name', () => {
+      renderComponent({ plugin });
+
+      const title = screen.getByText(plugin.name);
+      expect(title).toBeInTheDocument();
+    });
+
+    it('renders plugin load button', () => {
+      renderComponent({ plugin });
+
+      const loadButton = screen.getByText('Load');
+      expect(loadButton.tagName).toBe('BUTTON');
+      expect(loadButton).toBeInTheDocument();
+    });
+    it('should change button label to unload if plugin is active', () => {
+      renderComponent(
+        { plugin },
+        {
+          plugins: {
+            activePlugins: {
+              data: {
+                [plugin.hash]: plugin,
+              },
+              pluginsId: [plugin.hash],
+            },
+            list: PLUGINS_INITIAL_STATE_LIST_MOCK,
+          },
+        },
+      );
+
+      expect(screen.queryByTestId('toggle-plugin')).toHaveTextContent('Unload');
+    });
+    it('should change button label to load if plugin is not active', () => {
+      renderComponent({ plugin });
+      expect(screen.queryByTestId('toggle-plugin')).toHaveTextContent('Load');
+    });
+    it('should unload plugin after click', async () => {
+      mockedAxiosApiClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.Ok, plugin);
+      mockedAxiosApiClient.onGet(apiPath.getPlugin(plugin.hash)).reply(HttpStatusCode.Ok, plugin);
+      mockedAxiosClient.onGet(plugin.urls[0]).reply(HttpStatusCode.Ok, '');
+      const { store } = renderComponent(
+        { plugin },
+        {
+          plugins: {
+            activePlugins: {
+              data: {
+                [plugin.hash]: plugin,
+              },
+              pluginsId: [plugin.hash],
+            },
+            list: PLUGINS_INITIAL_STATE_LIST_MOCK,
+          },
+        },
+      );
+
+      await act(() => {
+        screen.queryByTestId('toggle-plugin')?.click();
+      });
+
+      const { activePlugins } = store.getState().plugins;
+      expect(activePlugins.pluginsId).toEqual([]);
+      expect(activePlugins.data).toEqual({});
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..f129d79d0797827601fbff4068bec1b27e5fca2e
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.tsx
@@ -0,0 +1,30 @@
+/* eslint-disable no-magic-numbers */
+import { Button } from '@/shared/Button';
+import { MinervaPlugin } from '@/types/models';
+import { useLoadPlugin } from './hooks/useLoadPlugin';
+
+export interface Props {
+  plugin: MinervaPlugin;
+}
+
+export const LoadPlugin = ({ plugin }: Props): JSX.Element => {
+  const { isPluginActive, togglePlugin, isPluginLoading } = useLoadPlugin({
+    hash: plugin.hash,
+    pluginUrl: plugin.urls[0],
+  });
+
+  return (
+    <div className="flex w-full items-center justify-between text-sm">
+      <span className="text-cetacean-blue">{plugin.name}</span>
+      <Button
+        variantStyles="secondary"
+        className="h-10 self-end rounded-e rounded-s text-xs font-medium"
+        onClick={togglePlugin}
+        data-testid="toggle-plugin"
+        disabled={isPluginLoading}
+      >
+        {isPluginActive ? 'Unload' : 'Load'}
+      </Button>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/hooks/useLoadPlugin.test.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/hooks/useLoadPlugin.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..04245fbf3a2191bdfc1344bee1c12d75137339c9
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/hooks/useLoadPlugin.test.ts
@@ -0,0 +1,88 @@
+/* eslint-disable no-magic-numbers */
+import { renderHook, waitFor } from '@testing-library/react';
+import { act } from 'react-dom/test-utils';
+import axios, { HttpStatusCode } from 'axios';
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
+import MockAdapter from 'axios-mock-adapter';
+import { PluginsManager } from '@/services/pluginsManager';
+import { pluginFixture } from '@/models/fixtures/pluginFixture';
+import { useLoadPlugin } from './useLoadPlugin';
+
+const mockedAxiosClient = new MockAdapter(axios);
+jest.mock('../../../../../../services/pluginsManager/pluginsManager');
+
+describe('useLoadPlugin', () => {
+  afterEach(() => {
+    jest.restoreAllMocks();
+  });
+  it('should unload plugin successfully', async () => {
+    const { Wrapper, store } = getReduxStoreWithActionsListener({
+      ...INITIAL_STORE_STATE_MOCK,
+      plugins: {
+        activePlugins: {
+          pluginsId: [pluginFixture.hash],
+          data: {
+            [pluginFixture.hash]: pluginFixture,
+          },
+        },
+        list: INITIAL_STORE_STATE_MOCK.plugins.list,
+      },
+    });
+
+    const {
+      result: {
+        current: { isPluginActive, isPluginLoading, togglePlugin },
+      },
+    } = renderHook(
+      () => useLoadPlugin({ hash: pluginFixture.hash, pluginUrl: pluginFixture.urls[0] }),
+      {
+        wrapper: Wrapper,
+      },
+    );
+
+    expect(isPluginActive).toBe(true);
+    expect(isPluginLoading).toBe(false);
+
+    act(() => {
+      togglePlugin();
+    });
+
+    const actions = store.getActions();
+    expect(actions[0]).toEqual({
+      payload: { pluginId: pluginFixture.hash },
+      type: 'plugins/removePlugin',
+    });
+  });
+  it('should load plugin successfully', async () => {
+    const hash = 'pluginHash';
+    const pluginUrl = 'http://example.com/plugin.js';
+    Math.max = jest.fn();
+    const { Wrapper } = getReduxStoreWithActionsListener(INITIAL_STORE_STATE_MOCK);
+    const pluginScript = `function init() {${Math.max(1, 2)}} init()`;
+
+    mockedAxiosClient.onGet(pluginUrl).reply(HttpStatusCode.Ok, pluginScript);
+
+    const {
+      result: {
+        current: { isPluginActive, isPluginLoading, togglePlugin },
+      },
+    } = renderHook(() => useLoadPlugin({ hash, pluginUrl }), {
+      wrapper: Wrapper,
+    });
+
+    expect(isPluginActive).toBe(false);
+    expect(isPluginLoading).toBe(false);
+
+    togglePlugin();
+
+    expect(Math.max).toHaveBeenCalledWith(1, 2);
+
+    await waitFor(() => {
+      expect(PluginsManager.setHashedPlugin).toHaveBeenCalledWith({
+        pluginScript,
+        pluginUrl,
+      });
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/hooks/useLoadPlugin.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/hooks/useLoadPlugin.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d1b04f6549b8eb8b790302a7ff3ee31b45c822f7
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/hooks/useLoadPlugin.ts
@@ -0,0 +1,57 @@
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { isPluginActiveSelector, isPluginLoadingSelector } from '@/redux/plugins/plugins.selectors';
+import { removePlugin } from '@/redux/plugins/plugins.slice';
+import { PluginsManager } from '@/services/pluginsManager';
+import axios from 'axios';
+
+type UseLoadPluginReturnType = {
+  togglePlugin: () => void;
+  isPluginActive: boolean;
+  isPluginLoading: boolean;
+};
+
+type UseLoadPluginProps = {
+  hash: string;
+  pluginUrl: string;
+};
+
+export const useLoadPlugin = ({ hash, pluginUrl }: UseLoadPluginProps): UseLoadPluginReturnType => {
+  const isPluginActive = useAppSelector(state => isPluginActiveSelector(state, hash));
+  const isPluginLoading = useAppSelector(state => isPluginLoadingSelector(state, hash));
+
+  const dispatch = useAppDispatch();
+
+  const handleLoadPlugin = async (): Promise<void> => {
+    const response = await axios(pluginUrl);
+    const pluginScript = response.data;
+
+    /* eslint-disable no-new-func */
+    const loadPlugin = new Function(pluginScript);
+
+    PluginsManager.setHashedPlugin({
+      pluginUrl,
+      pluginScript,
+    });
+
+    loadPlugin();
+  };
+
+  const handleUnloadPlugin = (): void => {
+    dispatch(removePlugin({ pluginId: hash }));
+  };
+
+  const togglePlugin = (): void => {
+    if (isPluginActive) {
+      handleUnloadPlugin();
+    } else {
+      handleLoadPlugin();
+    }
+  };
+
+  return {
+    togglePlugin,
+    isPluginActive,
+    isPluginLoading,
+  };
+};
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/index.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e27e6ba35e4443188bf5a6e08a655ddb97b3262c
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/index.ts
@@ -0,0 +1 @@
+export { LoadPlugin } from './LoadPlugin.component';
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.test.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..10d387fbba06a482aa6a79be309671efaabfd01c
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.test.tsx
@@ -0,0 +1,163 @@
+/* eslint-disable no-magic-numbers */
+import { fireEvent, render, screen } from '@testing-library/react';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { InitialStoreState } from '@/utils/testing/getReduxStoreActionsListener';
+import { StoreType } from '@/redux/store';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import MockAdapter from 'axios-mock-adapter';
+import axios, { HttpStatusCode } from 'axios';
+import { apiPath } from '@/redux/apiPath';
+import { pluginFixture } from '@/models/fixtures/pluginFixture';
+import { act } from 'react-dom/test-utils';
+import { PLUGINS_INITIAL_STATE_LIST_MOCK } from '@/redux/plugins/plugins.mock';
+import { LoadPluginFromUrl } from './LoadPluginFromUrl.component';
+
+const mockedAxiosApiClient = mockNetworkResponse();
+const mockedAxiosClient = new MockAdapter(axios);
+
+const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStore);
+  return (
+    render(
+      <Wrapper>
+        <LoadPluginFromUrl />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('LoadPluginFromUrl - component', () => {
+  global.URL.canParse = jest.fn();
+
+  afterEach(() => {
+    jest.restoreAllMocks();
+  });
+  describe('when always', () => {
+    it('renders plugin input label', () => {
+      renderComponent();
+
+      const pluginInputLabel = screen.getByLabelText('URL:');
+      expect(pluginInputLabel).toBeInTheDocument();
+    });
+
+    it('renders plugin input', () => {
+      renderComponent();
+
+      const pluginInput = screen.getByTestId('load-plugin-input-url');
+      expect(pluginInput).toBeInTheDocument();
+    });
+
+    it('renders plugin load button', () => {
+      renderComponent();
+
+      const loadButton = screen.getByText('Load');
+      expect(loadButton.tagName).toBe('BUTTON');
+      expect(loadButton).toBeInTheDocument();
+    });
+    it('should unload plugin after click', async () => {
+      mockedAxiosApiClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.Ok, pluginFixture);
+      mockedAxiosApiClient
+        .onGet(apiPath.getPlugin(pluginFixture.hash))
+        .reply(HttpStatusCode.Ok, pluginFixture);
+      mockedAxiosClient.onGet(pluginFixture.urls[0]).reply(HttpStatusCode.Ok, '');
+
+      renderComponent();
+      const input = screen.getByTestId('load-plugin-input-url');
+      expect(input).toBeVisible();
+
+      act(() => {
+        fireEvent.change(input, { target: { value: pluginFixture.urls[0] } });
+      });
+
+      expect(input).toHaveValue(pluginFixture.urls[0]);
+
+      const button = screen.queryByTestId('load-plugin-button');
+      expect(button).toBeVisible();
+
+      act(() => {
+        button?.click();
+      });
+
+      expect(button).toBeDisabled();
+    });
+    it('should not load plugin if it`s loaded already', async () => {
+      global.URL.canParse = jest.fn().mockReturnValue(true);
+
+      const plugin = {
+        ...pluginFixture,
+        urls: ['https://example.com/min.js'],
+      };
+      mockedAxiosClient.onGet(plugin.urls[0]).reply(HttpStatusCode.Ok, '');
+
+      const { store } = renderComponent({
+        plugins: {
+          activePlugins: {
+            pluginsId: [plugin.hash],
+            data: {
+              [plugin.hash]: plugin,
+            },
+          },
+          list: PLUGINS_INITIAL_STATE_LIST_MOCK,
+        },
+      });
+      const input = screen.getByTestId('load-plugin-input-url');
+      expect(input).toBeVisible();
+
+      act(() => {
+        fireEvent.change(input, { target: { value: plugin.urls[0] } });
+      });
+
+      expect(input).toHaveValue(plugin.urls[0]);
+
+      const button = screen.getByTestId('load-plugin-button');
+      expect(button).not.toBeDisabled();
+      await act(() => {
+        button.click();
+      });
+
+      const { activePlugins } = store.getState().plugins;
+
+      expect(activePlugins).toEqual({
+        pluginsId: [plugin.hash],
+        data: {
+          [plugin.hash]: plugin,
+        },
+      });
+
+      expect(input).toHaveValue('');
+    });
+    it('should disable url input if url is empty', async () => {
+      renderComponent();
+      const input = screen.getByTestId('load-plugin-input-url');
+      expect(input).toBeVisible();
+
+      act(() => {
+        fireEvent.change(input, { target: { value: '' } });
+      });
+
+      expect(input).toHaveValue('');
+
+      const button = screen.getByTestId('load-plugin-button');
+      expect(button).toBeDisabled();
+    });
+
+    it('should disable url input if url is not correct', async () => {
+      global.URL.canParse = jest.fn().mockReturnValue(false);
+      renderComponent();
+      const input = screen.getByTestId('load-plugin-input-url');
+      expect(input).toBeVisible();
+
+      act(() => {
+        fireEvent.change(input, { target: { value: 'abcd' } });
+      });
+
+      expect(input).toHaveValue('abcd');
+
+      const button = screen.getByTestId('load-plugin-button');
+      expect(button).toBeDisabled();
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..f57224d048c4af8fd407c8c38cff19f111e8dccf
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.tsx
@@ -0,0 +1,31 @@
+import { Button } from '@/shared/Button';
+import { Input } from '@/shared/Input';
+import { useLoadPluginFromUrl } from './hooks/useLoadPluginFromUrl';
+
+export const LoadPluginFromUrl = (): JSX.Element => {
+  const { handleChangePluginUrl, handleLoadPlugin, isPending, pluginUrl } = useLoadPluginFromUrl();
+
+  return (
+    <div className="flex w-full">
+      <label className="flex w-full flex-col gap-2 text-sm text-cetacean-blue">
+        <span>URL:</span>
+        <Input
+          className="h-10 w-full flex-none bg-cultured p-3"
+          type="url"
+          value={pluginUrl}
+          onChange={handleChangePluginUrl}
+          data-testid="load-plugin-input-url"
+        />
+      </label>
+      <Button
+        variantStyles="secondary"
+        className="h-10 self-end rounded-e rounded-s text-xs font-medium"
+        onClick={handleLoadPlugin}
+        disabled={isPending}
+        data-testid="load-plugin-button"
+      >
+        Load
+      </Button>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/hooks/useLoadPluginFromUrl.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/hooks/useLoadPluginFromUrl.ts
new file mode 100644
index 0000000000000000000000000000000000000000..123e220ccc3e05c23d54bbcf62e8d9c607acb373
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/hooks/useLoadPluginFromUrl.ts
@@ -0,0 +1,57 @@
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { activePluginsDataSelector } from '@/redux/plugins/plugins.selectors';
+import { PluginsManager } from '@/services/pluginsManager';
+import axios from 'axios';
+import { ChangeEvent, useMemo, useState } from 'react';
+
+type UseLoadPluginReturnType = {
+  handleChangePluginUrl: (event: ChangeEvent<HTMLInputElement>) => void;
+  handleLoadPlugin: () => Promise<void>;
+  isPending: boolean;
+  pluginUrl: string;
+};
+
+export const useLoadPluginFromUrl = (): UseLoadPluginReturnType => {
+  const [pluginUrl, setPluginUrl] = useState('');
+  const [isLoading, setIsLoading] = useState(false);
+  const activePlugins = useAppSelector(activePluginsDataSelector);
+
+  const isPending = useMemo(
+    () => !pluginUrl || isLoading || !URL.canParse(pluginUrl),
+    [pluginUrl, isLoading],
+  );
+
+  const handleLoadPlugin = async (): Promise<void> => {
+    try {
+      setIsLoading(true);
+      const response = await axios(pluginUrl);
+      const pluginScript = response.data;
+
+      /* eslint-disable no-new-func */
+      const loadPlugin = new Function(pluginScript);
+
+      const hash = PluginsManager.setHashedPlugin({
+        pluginUrl,
+        pluginScript,
+      });
+
+      if (!(hash in activePlugins)) {
+        loadPlugin();
+      }
+
+      setPluginUrl('');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+  const handleChangePluginUrl = (event: ChangeEvent<HTMLInputElement>): void => {
+    setPluginUrl(event.target.value);
+  };
+
+  return {
+    handleChangePluginUrl,
+    handleLoadPlugin,
+    isPending,
+    pluginUrl,
+  };
+};
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/index.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cedb0f665553574022fb55f4f00ef9678b546f1d
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/index.ts
@@ -0,0 +1 @@
+export { LoadPluginFromUrl } from './LoadPluginFromUrl.component';
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/PrivateActivePlugins/PrivateActivePlugins.component.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/PrivateActivePlugins/PrivateActivePlugins.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..557b997413b41d2299194cfe1d08caa92907c45f
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/PrivateActivePlugins/PrivateActivePlugins.component.tsx
@@ -0,0 +1,8 @@
+import { privateActivePluginsSelector } from '@/redux/plugins/plugins.selectors';
+import { useSelector } from 'react-redux';
+import { LoadPlugin } from '../LoadPlugin';
+
+export const PrivateActivePlugins = (): React.ReactNode => {
+  const privateActivePlugins = useSelector(privateActivePluginsSelector);
+  return privateActivePlugins.map(plugin => <LoadPlugin key={plugin.hash} plugin={plugin} />);
+};
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/PrivateActivePlugins/index.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/PrivateActivePlugins/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4a8bc8b5fb91dbd12bfdff759888d4266870c8f5
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/PrivateActivePlugins/index.ts
@@ -0,0 +1 @@
+export { PrivateActivePlugins } from './PrivateActivePlugins.component';
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/PublicPlugins/PublicPlugins.component.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/PublicPlugins/PublicPlugins.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..674b88756126ae4460e8b81d5dfd06a1047b86cf
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/PublicPlugins/PublicPlugins.component.tsx
@@ -0,0 +1,9 @@
+import { publicPluginsListSelector } from '@/redux/plugins/plugins.selectors';
+import React from 'react';
+import { useSelector } from 'react-redux';
+import { LoadPlugin } from '../LoadPlugin';
+
+export const PublicPlugins = (): React.ReactNode => {
+  const publicPlugins = useSelector(publicPluginsListSelector);
+  return publicPlugins.map(plugin => <LoadPlugin key={plugin.hash} plugin={plugin} />);
+};
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/PublicPlugins/index.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/PublicPlugins/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7c1fd8a7776423954e1da451bdf1ba757e14a1db
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/PublicPlugins/index.ts
@@ -0,0 +1 @@
+export { PublicPlugins } from './PublicPlugins.component';
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/index.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..85f2fe7f30853779b57a030199940cd3055f8e3a
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/index.ts
@@ -0,0 +1 @@
+export { AvailablePluginsDrawer } from './AvailablePluginsDrawer.component';
diff --git a/src/components/Map/Drawer/Drawer.component.tsx b/src/components/Map/Drawer/Drawer.component.tsx
index 098c4f989ec233798af6de0addfbb28fca84b02e..de1aa94ea44f6f9e2203ea3a386e373cbce620d6 100644
--- a/src/components/Map/Drawer/Drawer.component.tsx
+++ b/src/components/Map/Drawer/Drawer.component.tsx
@@ -2,13 +2,14 @@ import { DRAWER_ROLE } from '@/components/Map/Drawer/Drawer.constants';
 import { drawerSelector } from '@/redux/drawer/drawer.selectors';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import { twMerge } from 'tailwind-merge';
-import { ReactionDrawer } from './ReactionDrawer';
-import { SearchDrawerWrapper as SearchDrawerContent } from './SearchDrawerWrapper';
-import { SubmapsDrawer } from './SubmapsDrawer';
-import { OverlaysDrawer } from './OverlaysDrawer';
+import { AvailablePluginsDrawer } from './AvailablePluginsDrawer';
 import { BioEntityDrawer } from './BioEntityDrawer/BioEntityDrawer.component';
 import { ExportDrawer } from './ExportDrawer';
+import { OverlaysDrawer } from './OverlaysDrawer';
 import { ProjectInfoDrawer } from './ProjectInfoDrawer';
+import { ReactionDrawer } from './ReactionDrawer';
+import { SearchDrawerWrapper as SearchDrawerContent } from './SearchDrawerWrapper';
+import { SubmapsDrawer } from './SubmapsDrawer';
 
 export const Drawer = (): JSX.Element => {
   const { isOpen, drawerName } = useAppSelector(drawerSelector);
@@ -28,6 +29,7 @@ export const Drawer = (): JSX.Element => {
       {isOpen && drawerName === 'bio-entity' && <BioEntityDrawer />}
       {isOpen && drawerName === 'project-info' && <ProjectInfoDrawer />}
       {isOpen && drawerName === 'export' && <ExportDrawer />}
+      {isOpen && drawerName === 'available-plugins' && <AvailablePluginsDrawer />}
     </div>
   );
 };
diff --git a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.test.tsx
index 1fb3437a0f779358067827ff463df4d3f8ca76c2..7d514e917e452c4c0f64e81846c12e3e65a7ba35 100644
--- a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.test.tsx
+++ b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.test.tsx
@@ -1,5 +1,4 @@
-import React from 'react';
-import { render, screen, fireEvent } from '@testing-library/react';
+import { fireEvent, render, screen } from '@testing-library/react';
 
 import { CheckboxFilter } from './CheckboxFilter.component';
 
@@ -9,14 +8,16 @@ const options = [
   { id: '3', label: 'Option 3' },
 ];
 
+const currentOptions = [{ id: '2', label: 'Option 2' }];
+
 describe('CheckboxFilter - component', () => {
   it('should render CheckboxFilter properly', () => {
-    render(<CheckboxFilter options={options} />);
+    render(<CheckboxFilter options={options} currentOptions={[]} />);
     expect(screen.getByTestId('search')).toBeInTheDocument();
   });
 
   it('should filter options based on search term', async () => {
-    render(<CheckboxFilter options={options} />);
+    render(<CheckboxFilter options={options} currentOptions={[]} />);
     const searchInput = screen.getByLabelText('search-input');
 
     fireEvent.change(searchInput, { target: { value: `Option 1` } });
@@ -28,7 +29,26 @@ describe('CheckboxFilter - component', () => {
 
   it('should handle checkbox value change', async () => {
     const onCheckedChange = jest.fn();
-    render(<CheckboxFilter options={options} onCheckedChange={onCheckedChange} />);
+    render(
+      <CheckboxFilter currentOptions={[]} options={options} onCheckedChange={onCheckedChange} />,
+    );
+    const checkbox = screen.getByLabelText('Option 1');
+
+    fireEvent.click(checkbox);
+
+    expect(onCheckedChange).toHaveBeenCalledWith([{ id: '1', label: 'Option 1' }]);
+  });
+
+  it('should handle radio value change', async () => {
+    const onCheckedChange = jest.fn();
+    render(
+      <CheckboxFilter
+        currentOptions={[]}
+        type="radio"
+        options={options}
+        onCheckedChange={onCheckedChange}
+      />,
+    );
     const checkbox = screen.getByLabelText('Option 1');
 
     fireEvent.click(checkbox);
@@ -38,7 +58,9 @@ describe('CheckboxFilter - component', () => {
 
   it('should call onFilterChange when searching new term', async () => {
     const onFilterChange = jest.fn();
-    render(<CheckboxFilter options={options} onFilterChange={onFilterChange} />);
+    render(
+      <CheckboxFilter currentOptions={[]} options={options} onFilterChange={onFilterChange} />,
+    );
     const searchInput = screen.getByLabelText('search-input');
 
     fireEvent.change(searchInput, { target: { value: 'Option 1' } });
@@ -46,7 +68,7 @@ describe('CheckboxFilter - component', () => {
     expect(onFilterChange).toHaveBeenCalledWith([{ id: '1', label: 'Option 1' }]);
   });
   it('should display message when no elements are found', async () => {
-    render(<CheckboxFilter options={options} />);
+    render(<CheckboxFilter currentOptions={[]} options={options} />);
     const searchInput = screen.getByLabelText('search-input');
 
     fireEvent.change(searchInput, { target: { value: 'Nonexistent Option' } });
@@ -55,13 +77,15 @@ describe('CheckboxFilter - component', () => {
   });
   it('should display message when options are empty', () => {
     const onFilterChange = jest.fn();
-    render(<CheckboxFilter options={[]} onFilterChange={onFilterChange} />);
+    render(<CheckboxFilter currentOptions={[]} options={[]} onFilterChange={onFilterChange} />);
 
     expect(screen.getByText('No matching elements found.')).toBeInTheDocument();
   });
   it('should handle multiple checkbox selection', () => {
     const onCheckedChange = jest.fn();
-    render(<CheckboxFilter options={options} onCheckedChange={onCheckedChange} />);
+    render(
+      <CheckboxFilter currentOptions={[]} options={options} onCheckedChange={onCheckedChange} />,
+    );
 
     const checkbox1 = screen.getByLabelText('Option 1');
     const checkbox2 = screen.getByLabelText('Option 2');
@@ -74,9 +98,33 @@ describe('CheckboxFilter - component', () => {
       { id: '2', label: 'Option 2' },
     ]);
   });
+
+  it('should handle multiple change of radio selection', () => {
+    const onCheckedChange = jest.fn();
+    render(
+      <CheckboxFilter
+        currentOptions={[]}
+        options={options}
+        onCheckedChange={onCheckedChange}
+        type="radio"
+      />,
+    );
+
+    const checkbox1 = screen.getByLabelText('Option 1');
+    const checkbox2 = screen.getByLabelText('Option 2');
+
+    fireEvent.click(checkbox1);
+    expect(onCheckedChange).toHaveBeenCalledWith([{ id: '1', label: 'Option 1' }]);
+
+    fireEvent.click(checkbox2);
+    expect(onCheckedChange).toHaveBeenCalledWith([{ id: '2', label: 'Option 2' }]);
+  });
+
   it('should handle unchecking a checkbox', () => {
     const onCheckedChange = jest.fn();
-    render(<CheckboxFilter options={options} onCheckedChange={onCheckedChange} />);
+    render(
+      <CheckboxFilter currentOptions={[]} options={options} onCheckedChange={onCheckedChange} />,
+    );
 
     const checkbox = screen.getByLabelText('Option 1');
 
@@ -86,19 +134,19 @@ describe('CheckboxFilter - component', () => {
     expect(onCheckedChange).toHaveBeenCalledWith([]);
   });
   it('should render search input when isSearchEnabled is true', () => {
-    render(<CheckboxFilter options={options} />);
+    render(<CheckboxFilter currentOptions={[]} options={options} />);
     const searchInput = screen.getByLabelText('search-input');
     expect(searchInput).toBeInTheDocument();
   });
 
   it('should not render search input when isSearchEnabled is false', () => {
-    render(<CheckboxFilter options={options} isSearchEnabled={false} />);
+    render(<CheckboxFilter currentOptions={[]} options={options} isSearchEnabled={false} />);
     const searchInput = screen.queryByLabelText('search-input');
     expect(searchInput).not.toBeInTheDocument();
   });
 
   it('should not filter options based on search input when isSearchEnabled is false', () => {
-    render(<CheckboxFilter options={options} isSearchEnabled={false} />);
+    render(<CheckboxFilter currentOptions={[]} options={options} isSearchEnabled={false} />);
     const searchInput = screen.queryByLabelText('search-input');
     expect(searchInput).not.toBeInTheDocument();
     options.forEach(option => {
@@ -106,4 +154,15 @@ describe('CheckboxFilter - component', () => {
       expect(checkboxLabel).toBeInTheDocument();
     });
   });
+
+  it('should set checked param based on currentOptions prop', async () => {
+    render(<CheckboxFilter options={options} currentOptions={currentOptions} />);
+    const option1: HTMLInputElement = screen.getByLabelText('Option 1');
+    const option2: HTMLInputElement = screen.getByLabelText('Option 2');
+    const option3: HTMLInputElement = screen.getByLabelText('Option 3');
+
+    expect(option1.checked).toBe(false);
+    expect(option2.checked).toBe(true);
+    expect(option3.checked).toBe(false);
+  });
 });
diff --git a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx
index 54ac8df4fc0f8634d21a474a3d4cfca07b239434..e02000ab89c0b39f464420e9ff7deb2a1385f205 100644
--- a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx
+++ b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.component.tsx
@@ -1,23 +1,27 @@
 /* eslint-disable no-magic-numbers */
+import lensIcon from '@/assets/vectors/icons/lens.svg';
 import Image from 'next/image';
 import React, { useEffect, useState } from 'react';
-import lensIcon from '@/assets/vectors/icons/lens.svg';
 import { twMerge } from 'tailwind-merge';
-
-export type CheckboxItem = { id: string; label: string };
+import { CheckboxItem } from './CheckboxFilter.types';
+import { OptionInput } from './OptionInput';
 
 type CheckboxFilterProps = {
   options: CheckboxItem[];
+  currentOptions: CheckboxItem[];
   onFilterChange?: (filteredItems: CheckboxItem[]) => void;
   onCheckedChange?: (filteredItems: CheckboxItem[]) => void;
   isSearchEnabled?: boolean;
+  type?: 'checkbox' | 'radio';
 };
 
 export const CheckboxFilter = ({
   options,
+  currentOptions = [],
   onFilterChange,
   onCheckedChange,
   isSearchEnabled = true,
+  type = 'checkbox',
 }: CheckboxFilterProps): React.ReactNode => {
   const [searchTerm, setSearchTerm] = useState('');
   const [filteredOptions, setFilteredOptions] = useState<CheckboxItem[]>(options);
@@ -39,14 +43,19 @@ export const CheckboxFilter = ({
   };
 
   const handleCheckboxChange = (option: CheckboxItem): void => {
-    const newCheckedCheckboxes = checkedCheckboxes.includes(option)
-      ? checkedCheckboxes.filter(item => item !== option)
+    const newCheckedCheckboxes = checkedCheckboxes.some(item => item.id === option.id)
+      ? checkedCheckboxes.filter(item => item.id !== option.id)
       : [...checkedCheckboxes, option];
 
     setCheckedCheckboxes(newCheckedCheckboxes);
     onCheckedChange?.(newCheckedCheckboxes);
   };
 
+  const handleRadioChange = (option: CheckboxItem): void => {
+    setCheckedCheckboxes([option]);
+    onCheckedChange?.([option]);
+  };
+
   useEffect(() => {
     setFilteredOptions(options);
   }, [options]);
@@ -86,15 +95,13 @@ export const CheckboxFilter = ({
           <ul className="columns-2 gap-8">
             {filteredOptions.map(option => (
               <li key={option.id} className="mb-5 flex items-center gap-x-2">
-                <input
-                  type="checkbox"
-                  id={option.id}
-                  className=" h-4 w-4 shrink-0 accent-primary-500"
-                  onChange={(): void => handleCheckboxChange(option)}
+                <OptionInput
+                  option={option}
+                  currentOptions={currentOptions}
+                  handleRadioChange={handleRadioChange}
+                  handleCheckboxChange={handleCheckboxChange}
+                  type={type}
                 />
-                <label htmlFor={option.id} className="break-all text-sm">
-                  {option.label}
-                </label>
               </li>
             ))}
           </ul>
diff --git a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.types.ts b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1f060532b1071c39b9e1897b16e18e1c8bd4b173
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/CheckboxFilter.types.ts
@@ -0,0 +1 @@
+export type CheckboxItem = { id: string; label: string };
diff --git a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/OptionInput/OptionInput.component.tsx b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/OptionInput/OptionInput.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..61611797079b5af037629edf9f242f96b01d0f37
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/OptionInput/OptionInput.component.tsx
@@ -0,0 +1,48 @@
+import { twMerge } from 'tailwind-merge';
+import { CheckboxItem } from '../CheckboxFilter.types';
+
+interface Props {
+  option: CheckboxItem;
+  currentOptions: CheckboxItem[];
+  type: 'checkbox' | 'radio';
+  handleCheckboxChange(option: CheckboxItem): void;
+  handleRadioChange(option: CheckboxItem): void;
+}
+
+export const OptionInput = ({
+  option,
+  currentOptions = [],
+  type,
+  handleCheckboxChange,
+  handleRadioChange,
+}: Props): React.ReactNode => {
+  const isChecked = Boolean(currentOptions.find(currentOption => currentOption.id === option.id));
+
+  const handleChange = (): void => {
+    switch (type) {
+      case 'checkbox':
+        handleCheckboxChange(option);
+        break;
+      case 'radio':
+        handleRadioChange(option);
+        break;
+      default:
+        throw new Error(`${type} is unknown option input type`);
+    }
+  };
+
+  return (
+    <label className="flex items-center gap-x-2">
+      <input
+        type={type}
+        className={twMerge(
+          'h-4 w-4 shrink-0 accent-primary-500',
+          type === 'radio' && 'rounded-full',
+        )}
+        onChange={handleChange}
+        checked={isChecked}
+      />
+      <div className="break-all text-sm">{option.label}</div>
+    </label>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/OptionInput/index.ts b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/OptionInput/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..55a9b8f1c138359e5af93aaf0ec5b88cc6e7eeff
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/CheckboxFilter/OptionInput/index.ts
@@ -0,0 +1 @@
+export { OptionInput } from './OptionInput.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..9fa8624b161e701d4836820a0d008319f53c1aa9
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.test.tsx
@@ -0,0 +1,210 @@
+/* eslint-disable no-magic-numbers */
+import { compartmentPathwaysDetailsFixture } from '@/models/fixtures/compartmentPathways';
+import { configurationFixture } from '@/models/fixtures/configurationFixture';
+import { modelsFixture } from '@/models/fixtures/modelsFixture';
+import { statisticsFixture } from '@/models/fixtures/statisticsFixture';
+import { apiPath } from '@/redux/apiPath';
+import { CONFIGURATION_INITIAL_STORE_MOCK } from '@/redux/configuration/configuration.mock';
+import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
+import { AppDispatch, RootState } from '@/redux/store';
+import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { InitialStoreState } from '@/utils/testing/getReduxWrapperWithStore';
+import { render, screen } from '@testing-library/react';
+import { HttpStatusCode } from 'axios';
+import { act } from 'react-dom/test-utils';
+import { MockStoreEnhanced } from 'redux-mock-store';
+import { ELEMENTS_COLUMNS } from '../ExportCompound/ExportCompound.constant';
+import { Elements } from './Elements.component';
+
+const mockedAxiosClient = mockNetworkNewAPIResponse();
+
+const renderComponent = (
+  initialStore?: InitialStoreState,
+): { store: MockStoreEnhanced<Partial<RootState>, AppDispatch> } => {
+  const { Wrapper, store } = getReduxStoreWithActionsListener(initialStore);
+  return (
+    render(
+      <Wrapper>
+        <Elements />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('Elements - component', () => {
+  it('should render all elements sections', () => {
+    renderComponent({
+      ...INITIAL_STORE_STATE_MOCK,
+      configuration: {
+        ...CONFIGURATION_INITIAL_STORE_MOCK,
+        main: {
+          ...CONFIGURATION_INITIAL_STORE_MOCK.main,
+          data: {
+            ...configurationFixture,
+            miriamTypes: {
+              compartment_label: {
+                commonName: 'Compartment',
+                homepage: '',
+                registryIdentifier: '',
+                uris: [''],
+              },
+            },
+          },
+        },
+      },
+      statistics: {
+        data: {
+          ...statisticsFixture,
+          elementAnnotations: {
+            compartment_label: 1,
+            pathway: 0,
+          },
+        },
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+      compartmentPathways: {
+        data: compartmentPathwaysDetailsFixture,
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+
+    const annotations = screen.getByText('Select annotations');
+    const includedCompartmentPathways = screen.getByText('Select included compartment / pathways');
+    const excludedCompartmentPathways = screen.getByText('Select excluded compartment / pathways');
+    const downloadButton = screen.getByText('Download');
+
+    expect(annotations).toBeVisible();
+    expect(includedCompartmentPathways).toBeVisible();
+    expect(excludedCompartmentPathways).toBeVisible();
+    expect(downloadButton).toBeVisible();
+  });
+  it('should handle download button click and dispatch proper data', async () => {
+    mockedAxiosClient.onPost(apiPath.downloadElementsCsv()).reply(HttpStatusCode.Ok, 'test');
+    const FIRST_COMPARMENT_PATHWAY_NAME = compartmentPathwaysDetailsFixture[0].name;
+    const FIRST_COMPARMENT_PATHWAY_ID = compartmentPathwaysDetailsFixture[0].id;
+    const SECOND_COMPARMENT_PATHWAY_NAME = compartmentPathwaysDetailsFixture[1].name;
+    const SECOND_COMPARMENT_PATHWAY_ID = compartmentPathwaysDetailsFixture[1].id;
+    const { store } = renderComponent({
+      ...INITIAL_STORE_STATE_MOCK,
+      configuration: {
+        ...CONFIGURATION_INITIAL_STORE_MOCK,
+        main: {
+          ...CONFIGURATION_INITIAL_STORE_MOCK.main,
+          data: {
+            ...configurationFixture,
+            miriamTypes: {
+              compartment_label: {
+                commonName: 'Compartment',
+                homepage: '',
+                registryIdentifier: '',
+                uris: [''],
+              },
+            },
+          },
+        },
+      },
+      statistics: {
+        data: {
+          ...statisticsFixture,
+          elementAnnotations: {
+            compartment_label: 1,
+            pathway: 0,
+          },
+        },
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+      compartmentPathways: {
+        data: compartmentPathwaysDetailsFixture,
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+      models: {
+        data: modelsFixture,
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+
+    const annotations = screen.getByText('Select annotations');
+
+    await act(() => {
+      annotations.click();
+    });
+    const annotationInput = screen.getByLabelText('Compartment');
+
+    await act(() => {
+      annotationInput.click();
+    });
+
+    expect(annotationInput).toBeChecked();
+
+    const includedCompartmentPathways = screen.getByText('Select included compartment / pathways');
+
+    await act(() => {
+      includedCompartmentPathways.click();
+    });
+    const includedCompartmentPathwaysInput = screen.getAllByLabelText(
+      FIRST_COMPARMENT_PATHWAY_NAME,
+    )[0];
+
+    await act(() => {
+      includedCompartmentPathwaysInput.click();
+    });
+
+    expect(includedCompartmentPathwaysInput).toBeChecked();
+
+    const excludedCompartmentPathways = screen.getByText('Select excluded compartment / pathways');
+
+    await act(() => {
+      excludedCompartmentPathways.click();
+    });
+    const excludedCompartmentPathwaysInput = screen.getAllByLabelText(
+      SECOND_COMPARMENT_PATHWAY_NAME,
+    )[1];
+
+    await act(() => {
+      excludedCompartmentPathwaysInput.click();
+    });
+
+    expect(excludedCompartmentPathwaysInput).toBeChecked();
+
+    const downloadButton = screen.getByText('Download');
+
+    await act(() => {
+      downloadButton.click();
+    });
+
+    const actions = store.getActions();
+
+    const firstAction = actions[0];
+    expect(firstAction.meta.arg).toEqual({
+      columns: ELEMENTS_COLUMNS,
+      submaps: modelsFixture.map(item => item.idObject),
+      annotations: ['compartment_label'],
+      includedCompartmentIds: [FIRST_COMPARMENT_PATHWAY_ID],
+      excludedCompartmentIds: [SECOND_COMPARMENT_PATHWAY_ID],
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx
index fcf01b6a0c8fd6cae6b847e245f70e3d072508e7..d8993b4e914f047d36d44732dcfe074c080f90f0 100644
--- a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx
+++ b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.tsx
@@ -1,12 +1,11 @@
 import { Export } from '../ExportCompound';
+import { ANNOTATIONS_TYPE } from '../ExportCompound/ExportCompound.constant';
 
 export const Elements = (): React.ReactNode => {
   return (
     <div data-testid="elements-tab">
       <Export>
-        <Export.Types />
-        <Export.Columns />
-        <Export.Annotations />
+        <Export.Annotations type={ANNOTATIONS_TYPE.ELEMENTS} />
         <Export.IncludedCompartmentPathways />
         <Export.ExcludedCompartmentPathways />
         <Export.DownloadElements />
diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.utils.ts b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.utils.ts
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.test.tsx
index df19cb66cbdd04c7511105db937cf4f5f41be111..9ce4c9db49f0d1c0fc1619ad8c5d4d1cc13c5eb0 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.test.tsx
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.test.tsx
@@ -6,7 +6,10 @@ import {
 import { StoreType } from '@/redux/store';
 import { statisticsFixture } from '@/models/fixtures/statisticsFixture';
 import { act } from 'react-dom/test-utils';
+import { CONFIGURATION_INITIAL_STORE_MOCK } from '@/redux/configuration/configuration.mock';
+import { configurationFixture } from '@/models/fixtures/configurationFixture';
 import { Annotations } from './Annotations.component';
+import { ANNOTATIONS_TYPE } from '../ExportCompound.constant';
 
 const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
   const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
@@ -14,7 +17,7 @@ const renderComponent = (initialStoreState: InitialStoreState = {}): { store: St
   return (
     render(
       <Wrapper>
-        <Annotations />
+        <Annotations type={ANNOTATIONS_TYPE.ELEMENTS} />
       </Wrapper>,
     ),
     {
@@ -26,11 +29,28 @@ const renderComponent = (initialStoreState: InitialStoreState = {}): { store: St
 describe('Annotations - component', () => {
   it('should display annotations checkboxes when fetching data is successful', async () => {
     renderComponent({
+      configuration: {
+        ...CONFIGURATION_INITIAL_STORE_MOCK,
+        main: {
+          ...CONFIGURATION_INITIAL_STORE_MOCK.main,
+          data: {
+            ...configurationFixture,
+            miriamTypes: {
+              compartment_label: {
+                commonName: 'Compartment',
+                homepage: '',
+                registryIdentifier: '',
+                uris: [''],
+              },
+            },
+          },
+        },
+      },
       statistics: {
         data: {
           ...statisticsFixture,
           elementAnnotations: {
-            compartment: 1,
+            compartment_label: 1,
             pathway: 0,
           },
         },
@@ -54,7 +74,7 @@ describe('Annotations - component', () => {
 
     await waitFor(() => {
       expect(screen.getByTestId('checkbox-filter')).toBeInTheDocument();
-      expect(screen.getByLabelText('compartment')).toBeInTheDocument();
+      expect(screen.getByLabelText('Compartment')).toBeInTheDocument();
       expect(screen.getByLabelText('search-input')).toBeInTheDocument();
     });
   });
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.tsx
index 6f7034f871d9034f2a038493d426d6784d552b02..bd065f025aeb52bd4279b9cc3b362ca902049217 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.tsx
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.component.tsx
@@ -1,29 +1,39 @@
-import { useContext } from 'react';
+import { ZERO } from '@/constants/common';
+import { miramiTypesSelector } from '@/redux/configuration/configuration.selectors';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import {
-  elementAnnotationsSelector,
   loadingStatisticsSelector,
+  statisticsDataSelector,
 } from '@/redux/statistics/statistics.selectors';
-import { ZERO } from '@/constants/common';
+import { useContext } from 'react';
 import { CheckboxFilter } from '../../CheckboxFilter';
 import { CollapsibleSection } from '../../CollapsibleSection';
 import { ExportContext } from '../ExportCompound.context';
+import { AnnotationsType } from './Annotations.types';
+import { getAnnotationsCheckboxElements } from './Annotations.utils';
 
-export const Annotations = (): React.ReactNode => {
-  const { setAnnotations } = useContext(ExportContext);
+type AnnotationsProps = {
+  type: AnnotationsType;
+};
+
+export const Annotations = ({ type }: AnnotationsProps): React.ReactNode => {
+  const { setAnnotations, data } = useContext(ExportContext);
+  const currentAnnotations = data.annotations;
   const loadingStatistics = useAppSelector(loadingStatisticsSelector);
-  const elementAnnotations = useAppSelector(elementAnnotationsSelector);
+  const statistics = useAppSelector(statisticsDataSelector);
+  const miramiTypes = useAppSelector(miramiTypesSelector);
   const isPending = loadingStatistics === 'pending';
-
-  const mappedElementAnnotations = elementAnnotations
-    ? Object.keys(elementAnnotations)?.map(el => ({ id: el, label: el }))
-    : [];
+  const checkboxElements = getAnnotationsCheckboxElements({ type, statistics, miramiTypes });
 
   return (
     <CollapsibleSection title="Select annotations">
       {isPending && <p>Loading...</p>}
-      {!isPending && mappedElementAnnotations && mappedElementAnnotations.length > ZERO && (
-        <CheckboxFilter options={mappedElementAnnotations} onCheckedChange={setAnnotations} />
+      {!isPending && checkboxElements && checkboxElements.length > ZERO && (
+        <CheckboxFilter
+          options={checkboxElements}
+          currentOptions={currentAnnotations}
+          onCheckedChange={setAnnotations}
+        />
       )}
     </CollapsibleSection>
   );
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.types.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..15ae345efceb1830a1d3c6ff42533d3dc5feaf58
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.types.ts
@@ -0,0 +1,3 @@
+import { ANNOTATIONS_TYPE } from '../ExportCompound.constant';
+
+export type AnnotationsType = (typeof ANNOTATIONS_TYPE)[keyof typeof ANNOTATIONS_TYPE];
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.utils.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.utils.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9a12c973e87d3148f47bb5ff69612362595c94e6
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.utils.test.ts
@@ -0,0 +1,98 @@
+import { getAnnotationsCheckboxElements } from './Annotations.utils';
+
+describe('getAnnotationsCheckboxElements', () => {
+  const statisticsMock = {
+    elementAnnotations: {
+      chebi: 2,
+      mesh: 0,
+      reactome: 1,
+    },
+    publications: 1234,
+    reactionAnnotations: {
+      brenda: 0,
+      reactome: 3,
+      rhea: 1,
+    },
+  };
+
+  const miramiTypeMock = {
+    commonName: 'Name',
+    homepage: '',
+    registryIdentifier: '',
+    uris: [''],
+  };
+
+  const miramiTypesMock = {
+    chebi: {
+      ...miramiTypeMock,
+      commonName: 'Chebi',
+    },
+    mesh: {
+      ...miramiTypeMock,
+      commonName: 'MeSH',
+    },
+    reactome: {
+      ...miramiTypeMock,
+      commonName: 'Reactome',
+    },
+    rhea: {
+      ...miramiTypeMock,
+      commonName: 'Rhea',
+    },
+    brenda: {
+      ...miramiTypeMock,
+      commonName: 'BRENDA',
+    },
+    gene_ontology: {
+      ...miramiTypeMock,
+      commonName: 'Gene Ontology',
+    },
+  };
+
+  it('returns an empty array when statistics or miramiTypes are undefined', () => {
+    const result = getAnnotationsCheckboxElements({
+      type: 'Elements',
+      statistics: undefined,
+      miramiTypes: undefined,
+    });
+    expect(result).toEqual([]);
+  });
+
+  it('returns checkbox elements for element annotations sorted by label', () => {
+    const result = getAnnotationsCheckboxElements({
+      type: 'Elements',
+      statistics: statisticsMock,
+      miramiTypes: miramiTypesMock,
+    });
+    expect(result).toEqual([
+      { id: 'chebi', label: 'Chebi' },
+      { id: 'reactome', label: 'Reactome' },
+    ]);
+  });
+
+  it('returns checkbox elements for reaction annotations sorted by count', () => {
+    const result = getAnnotationsCheckboxElements({
+      type: 'Network',
+      statistics: statisticsMock,
+      miramiTypes: miramiTypesMock,
+    });
+    expect(result).toEqual([
+      { id: 'reactome', label: 'Reactome' },
+      { id: 'rhea', label: 'Rhea' },
+    ]);
+  });
+
+  it('returns an empty array when no annotations have count greater than 0', () => {
+    const statisticsMockEmpty = {
+      elementAnnotations: { annotation1: 0, annotation2: 0 },
+      publications: 0,
+      reactionAnnotations: { annotation1: 0, annotation2: 0 },
+    };
+    const result = getAnnotationsCheckboxElements({
+      type: 'Elements',
+      statistics: statisticsMockEmpty,
+      miramiTypes: miramiTypesMock,
+    });
+    expect(result).toEqual([]);
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.utils.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.utils.ts
new file mode 100644
index 0000000000000000000000000000000000000000..35e31e656c3ce6cc7ea1c2e08b8e09e6d9efa004
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Annotations/Annotations.utils.ts
@@ -0,0 +1,51 @@
+/* eslint-disable no-magic-numbers */
+import { ConfigurationMiramiTypes, Statistics } from '@/types/models';
+import { ANNOTATIONS_TYPE } from '../ExportCompound.constant';
+import { AnnotationsType } from './Annotations.types';
+
+type CheckboxElement = { id: string; label: string };
+
+type CheckboxElements = CheckboxElement[];
+
+type GetAnnotationsCheckboxElements = {
+  type: AnnotationsType;
+  statistics: Statistics | undefined;
+  miramiTypes: ConfigurationMiramiTypes | undefined;
+};
+
+const sortByCount = (countA: number, countB: number): number => {
+  return countA > countB ? -1 : 1;
+};
+
+const mapToCheckboxElement = (
+  annotation: string,
+  miramiTypes: ConfigurationMiramiTypes,
+): CheckboxElement => ({
+  id: annotation,
+  label: miramiTypes[annotation].commonName,
+});
+
+const filterAnnotationsByCount = (annotations: Record<string, number>): string[] => {
+  return Object.keys(annotations).filter(annotation => annotations[annotation] > 0);
+};
+
+export const getAnnotationsCheckboxElements = ({
+  type,
+  statistics,
+  miramiTypes,
+}: GetAnnotationsCheckboxElements): CheckboxElements => {
+  if (!statistics || !miramiTypes) return [];
+
+  const annotations =
+    type === ANNOTATIONS_TYPE.ELEMENTS
+      ? statistics.elementAnnotations
+      : statistics.reactionAnnotations;
+
+  const availableAnnotations = filterAnnotationsByCount(annotations);
+
+  return availableAnnotations
+    .sort((firstAnnotation, secondAnnotation) =>
+      sortByCount(annotations[firstAnnotation], annotations[secondAnnotation]),
+    )
+    .map(annotation => mapToCheckboxElement(annotation, miramiTypes));
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.component.test.tsx
deleted file mode 100644
index 381ba5cc9c7fb3f22761c28516e469633a262a85..0000000000000000000000000000000000000000
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.component.test.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { render, screen } from '@testing-library/react';
-import { act } from 'react-dom/test-utils';
-import { Columns } from './Columns.component';
-
-describe('Columns - component', () => {
-  it('should display select column accordion', async () => {
-    render(<Columns />);
-
-    expect(screen.getByText('Select column')).toBeInTheDocument();
-    expect(screen.queryByTestId('checkbox-filter')).not.toBeVisible();
-  });
-  it('should display columns checkboxes', async () => {
-    render(<Columns />);
-
-    expect(screen.getByText('Select column')).toBeInTheDocument();
-    expect(screen.queryByTestId('checkbox-filter')).not.toBeVisible();
-
-    const navigationButton = screen.getByTestId('accordion-item-button');
-    act(() => {
-      navigationButton.click();
-    });
-
-    expect(screen.queryByTestId('checkbox-filter')).toBeVisible();
-    expect(screen.queryByLabelText('References')).toBeVisible();
-  });
-});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.component.tsx
deleted file mode 100644
index 954a4c60a4354f675d4c7bab265f45d69c384039..0000000000000000000000000000000000000000
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.component.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { useContext } from 'react';
-import { CheckboxFilter } from '../../CheckboxFilter';
-import { CollapsibleSection } from '../../CollapsibleSection';
-import { COLUMNS } from './Columns.constants';
-import { ExportContext } from '../ExportCompound.context';
-
-export const Columns = (): React.ReactNode => {
-  const { setColumns } = useContext(ExportContext);
-
-  return (
-    <CollapsibleSection title="Select column">
-      <CheckboxFilter options={COLUMNS} isSearchEnabled={false} onCheckedChange={setColumns} />
-    </CollapsibleSection>
-  );
-};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.constants.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.constants.tsx
deleted file mode 100644
index e2ece6b51ec445bd3c3b172120ce8679d5fe795c..0000000000000000000000000000000000000000
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/Columns.constants.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-export const COLUMNS = [
-  {
-    id: 'id',
-    label: 'ID',
-  },
-  {
-    id: 'description',
-    label: 'Description',
-  },
-  {
-    id: 'modelId',
-    label: 'Map id',
-  },
-  {
-    id: 'mapName',
-    label: 'Map name',
-  },
-  {
-    id: 'symbol',
-    label: 'Symbol',
-  },
-  {
-    id: 'abbreviation',
-    label: 'Abbreviation',
-  },
-  {
-    id: 'synonyms',
-    label: 'Synonyms',
-  },
-  {
-    id: 'references',
-    label: 'References',
-  },
-  {
-    id: 'name',
-    label: 'Name',
-  },
-  {
-    id: 'type',
-    label: 'Type',
-  },
-  {
-    id: 'complexId',
-    label: 'Complex id',
-  },
-  {
-    id: 'complexName',
-    label: 'Complex name',
-  },
-  {
-    id: 'compartmentId',
-    label: 'Compartment/Pathway id',
-  },
-  {
-    id: 'compartmentName',
-    label: 'Compartment/Pathway name',
-  },
-  {
-    id: 'charge',
-    label: 'Charge',
-  },
-  {
-    id: 'fullName',
-    label: 'Full name',
-  },
-  {
-    id: 'formula',
-    label: 'Formula',
-  },
-  {
-    id: 'formerSymbols',
-    label: 'Former symbols',
-  },
-  {
-    id: 'linkedSubmodelId',
-    label: 'Linked submap id',
-  },
-  {
-    id: 'elementId',
-    label: 'Element external id',
-  },
-  {
-    id: 'ALL',
-    label: 'All',
-  },
-];
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/index.ts
deleted file mode 100644
index 167db8672847d14dac8a6cc038be63cfe105a582..0000000000000000000000000000000000000000
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Columns/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Columns } from './Columns.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadGraphics/DownloadGraphics.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadGraphics/DownloadGraphics.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..4d5833c4a7007e36b632a98cad2bcd4182bf7255
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadGraphics/DownloadGraphics.component.tsx
@@ -0,0 +1,13 @@
+import { Button } from '@/shared/Button';
+import { useContext } from 'react';
+import { ExportContext } from '../ExportCompound.context';
+
+export const DownloadGraphics = (): React.ReactNode => {
+  const { handleDownloadGraphics } = useContext(ExportContext);
+
+  return (
+    <div className="mt-6">
+      <Button onClick={handleDownloadGraphics}>Download</Button>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadGraphics/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadGraphics/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..755e63384991acb5a730640c0cb1c04e27058bcf
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadGraphics/index.ts
@@ -0,0 +1 @@
+export { DownloadGraphics } from './DownloadGraphics.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadNetwork/DownloadNetwork.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadNetwork/DownloadNetwork.tsx
index fbe769f0877561ab755049749e12577e13c1b005..8e0fb25dd7a80742635bc5039e63a74ceae686cc 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadNetwork/DownloadNetwork.tsx
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/DownloadNetwork/DownloadNetwork.tsx
@@ -2,7 +2,7 @@ import { useContext } from 'react';
 import { Button } from '@/shared/Button';
 import { ExportContext } from '../ExportCompound.context';
 
-export const DownloadElements = (): React.ReactNode => {
+export const DownloadNetwork = (): React.ReactNode => {
   const { handleDownloadNetwork } = useContext(ExportContext);
 
   return (
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.tsx
index a1de0816bef5e657fee1ee41ca4ed3f0937d0160..89007fae92f3b9ba261516041befe04ee004e3d9 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.tsx
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExcludedCompartmentPathways/ExcludedCompartmentPathways.component.tsx
@@ -1,21 +1,22 @@
-import { useContext } from 'react';
-import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { ZERO } from '@/constants/common';
 import {
   compartmentPathwaysDataSelector,
   loadingCompartmentPathwaysSelector,
 } from '@/redux/compartmentPathways/compartmentPathways.selectors';
-import { ZERO } from '@/constants/common';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { useContext } from 'react';
 import { CheckboxFilter } from '../../CheckboxFilter';
 import { CollapsibleSection } from '../../CollapsibleSection';
 import { ExportContext } from '../ExportCompound.context';
 import { getCompartmentPathwaysCheckboxElements } from '../utils/getCompartmentPathwaysCheckboxElements';
 
 export const ExcludedCompartmentPathways = (): React.ReactNode => {
-  const { setExcludedCompartmentPathways } = useContext(ExportContext);
+  const { setExcludedCompartmentPathways, data } = useContext(ExportContext);
+  const currentExcludedCompartmentPathways = data.excludedCompartmentPathways;
   const loadingCompartmentPathways = useAppSelector(loadingCompartmentPathwaysSelector);
   const isPending = loadingCompartmentPathways === 'pending';
   const compartmentPathways = useAppSelector(compartmentPathwaysDataSelector);
-  const checkboxElements = getCompartmentPathwaysCheckboxElements(compartmentPathways);
+  const checkboxElements = getCompartmentPathwaysCheckboxElements('excluded', compartmentPathways);
   const isCheckboxFilterVisible = !isPending && checkboxElements && checkboxElements.length > ZERO;
 
   return (
@@ -24,6 +25,7 @@ export const ExcludedCompartmentPathways = (): React.ReactNode => {
       {isCheckboxFilterVisible && (
         <CheckboxFilter
           options={checkboxElements}
+          currentOptions={currentExcludedCompartmentPathways}
           onCheckedChange={setExcludedCompartmentPathways}
         />
       )}
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.component.tsx
index 15f4767e22864d74979a577f62314f5af2d828de..52bc373224656a1994d53acf5fbda4b6a9619273 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.component.tsx
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.component.tsx
@@ -1,74 +1,133 @@
-import { ReactNode, useCallback, useMemo, useState } from 'react';
+import { FIRST_ARRAY_ELEMENT } from '@/constants/common';
+import { currentBackgroundSelector } from '@/redux/backgrounds/background.selectors';
+import { downloadElements, downloadNetwork } from '@/redux/export/export.thunks';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
-import { modelsIdsSelector } from '@/redux/models/models.selectors';
-import { CheckboxItem } from '../CheckboxFilter/CheckboxFilter.component';
-import { Types } from './Types';
-import { Columns } from './Columns';
+import { modelsDataSelector, modelsIdsSelector } from '@/redux/models/models.selectors';
+import { ReactNode, useCallback, useMemo, useState } from 'react';
+import { CheckboxItem } from '../CheckboxFilter/CheckboxFilter.types';
 import { Annotations } from './Annotations';
-import { ExcludedCompartmentPathways } from './ExcludedCompartmentPathways';
-import { IncludedCompartmentPathways } from './IncludedCompartmentPathways ';
 import { DownloadElements } from './DownloadElements/DownloadElements';
+import { DownloadGraphics } from './DownloadGraphics';
+import { DownloadNetwork } from './DownloadNetwork/DownloadNetwork';
+import { ExcludedCompartmentPathways } from './ExcludedCompartmentPathways';
+import { ELEMENTS_COLUMNS, NETWORK_COLUMNS } from './ExportCompound.constant';
 import { ExportContext } from './ExportCompound.context';
-import { getNetworkDownloadBodyRequest } from './utils/getNetworkBodyRequest';
+import { ImageFormat } from './ImageFormat';
+import { ImageSize } from './ImageSize';
+import { DEFAULT_IMAGE_SIZE } from './ImageSize/ImageSize.constants';
+import { ImageSize as ImageSizeType } from './ImageSize/ImageSize.types';
+import { IncludedCompartmentPathways } from './IncludedCompartmentPathways ';
+import { Submap } from './Submap';
 import { getDownloadElementsBodyRequest } from './utils/getDownloadElementsBodyRequest';
+import { getGraphicsDownloadUrl } from './utils/getGraphicsDownloadUrl';
+import { getModelExportZoom } from './utils/getModelExportZoom';
+import { getNetworkDownloadBodyRequest } from './utils/getNetworkBodyRequest';
 
 type ExportProps = {
   children: ReactNode;
 };
 
 export const Export = ({ children }: ExportProps): JSX.Element => {
-  const [types, setTypes] = useState<CheckboxItem[]>([]);
-  const [columns, setColumns] = useState<CheckboxItem[]>([]);
-  const [annotations, setAnnotations] = useState<CheckboxItem[]>([]);
+  const dispatch = useAppDispatch();
   const modelIds = useAppSelector(modelsIdsSelector);
+  const currentModels = useAppSelector(modelsDataSelector);
+  const currentBackground = useAppSelector(currentBackgroundSelector);
+  const [annotations, setAnnotations] = useState<CheckboxItem[]>([]);
   const [includedCompartmentPathways, setIncludedCompartmentPathways] = useState<CheckboxItem[]>(
     [],
   );
   const [excludedCompartmentPathways, setExcludedCompartmentPathways] = useState<CheckboxItem[]>(
     [],
   );
+  const [models, setModels] = useState<CheckboxItem[]>([]);
+  const [imageSize, setImageSize] = useState<ImageSizeType>(DEFAULT_IMAGE_SIZE);
+  const [imageFormats, setImageFormats] = useState<CheckboxItem[]>([]);
 
-  const handleDownloadElements = useCallback(() => {
-    getDownloadElementsBodyRequest({
-      types,
-      columns,
+  const handleDownloadElements = useCallback(async () => {
+    const body = getDownloadElementsBodyRequest({
+      columns: ELEMENTS_COLUMNS,
       modelIds,
       annotations,
       includedCompartmentPathways,
       excludedCompartmentPathways,
     });
-  }, [
-    types,
-    columns,
-    modelIds,
-    annotations,
-    includedCompartmentPathways,
-    excludedCompartmentPathways,
-  ]);
 
-  const handleDownloadNetwork = useCallback(() => {
-    getNetworkDownloadBodyRequest();
-  }, []);
+    dispatch(downloadElements(body));
+  }, [modelIds, annotations, includedCompartmentPathways, excludedCompartmentPathways, dispatch]);
+
+  const handleDownloadNetwork = useCallback(async () => {
+    const data = getNetworkDownloadBodyRequest({
+      columns: NETWORK_COLUMNS,
+      modelIds,
+      annotations,
+      includedCompartmentPathways,
+      excludedCompartmentPathways,
+    });
+
+    dispatch(downloadNetwork(data));
+  }, [modelIds, annotations, includedCompartmentPathways, excludedCompartmentPathways, dispatch]);
+
+  const handleDownloadGraphics = useCallback(async () => {
+    const modelId = models?.[FIRST_ARRAY_ELEMENT]?.id;
+    const model = currentModels.find(currentModel => currentModel.idObject === Number(modelId));
+
+    const url = getGraphicsDownloadUrl({
+      backgroundId: currentBackground?.id,
+      modelId: models?.[FIRST_ARRAY_ELEMENT]?.id,
+      handler: imageFormats?.[FIRST_ARRAY_ELEMENT]?.id,
+      zoom: getModelExportZoom(imageSize.width, model),
+    });
+
+    if (url) {
+      window.open(url);
+    }
+  }, [models, imageFormats, currentBackground, currentModels, imageSize.width]);
+
+  const globalContextDataValue = useMemo(
+    () => ({
+      annotations,
+      includedCompartmentPathways,
+      excludedCompartmentPathways,
+      models,
+      imageSize,
+      imageFormats,
+    }),
+    [
+      annotations,
+      includedCompartmentPathways,
+      excludedCompartmentPathways,
+      models,
+      imageSize,
+      imageFormats,
+    ],
+  );
 
   const globalContextValue = useMemo(
     () => ({
-      setTypes,
-      setColumns,
       setAnnotations,
       setIncludedCompartmentPathways,
       setExcludedCompartmentPathways,
+      setModels,
+      setImageSize,
+      setImageFormats,
       handleDownloadElements,
       handleDownloadNetwork,
+      handleDownloadGraphics,
+      data: globalContextDataValue,
     }),
-    [handleDownloadElements, handleDownloadNetwork],
+    [handleDownloadElements, handleDownloadNetwork, globalContextDataValue, handleDownloadGraphics],
   );
 
   return <ExportContext.Provider value={globalContextValue}>{children}</ExportContext.Provider>;
 };
 
-Export.Types = Types;
-Export.Columns = Columns;
 Export.Annotations = Annotations;
 Export.IncludedCompartmentPathways = IncludedCompartmentPathways;
 Export.ExcludedCompartmentPathways = ExcludedCompartmentPathways;
 Export.DownloadElements = DownloadElements;
+Export.Submap = Submap;
+Export.ImageSize = ImageSize;
+Export.ImageFormat = ImageFormat;
+Export.DownloadNetwork = DownloadNetwork;
+Export.DownloadGraphics = DownloadGraphics;
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.constant.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.constant.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a07ae4c58f7b2fa3ec8ef4f652c1d4c9dbca075b
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.constant.ts
@@ -0,0 +1,68 @@
+import { ExportContextType } from './ExportCompound.types';
+import { DEFAULT_IMAGE_SIZE } from './ImageSize/ImageSize.constants';
+
+export const ANNOTATIONS_TYPE = {
+  ELEMENTS: 'Elements',
+  NETWORK: 'Network',
+} as const;
+
+export const COLUMNS_TYPE = {
+  ELEMENTS: 'Elements',
+  NETWORK: 'Network',
+} as const;
+
+export const ELEMENTS_COLUMNS = [
+  'id',
+  'type',
+  'name',
+  'symbol',
+  'abbreviation',
+  'fullName',
+  'synonyms',
+  'formerSymbols',
+  'complexId',
+  'complexName',
+  'compartmentId',
+  'compartmentName',
+  'modelId',
+  'mapName',
+  'description',
+  'references',
+  'charge',
+  'formula',
+  'linkedSubmodelId',
+  'elementId',
+];
+
+export const NETWORK_COLUMNS = [
+  'id',
+  'type',
+  'reactantIds',
+  'productIds',
+  'modifierIds',
+  'description',
+  'reactionId',
+  'references',
+  'modelId',
+  'mapName',
+];
+
+export const EXPORT_CONTEXT_DEFAULT_VALUE: ExportContextType = {
+  setAnnotations: () => {},
+  setIncludedCompartmentPathways: () => {},
+  setExcludedCompartmentPathways: () => {},
+  setModels: () => {},
+  setImageSize: () => {},
+  setImageFormats: () => {},
+  handleDownloadElements: () => {},
+  handleDownloadNetwork: () => {},
+  handleDownloadGraphics: () => {},
+  data: {
+    annotations: [],
+    includedCompartmentPathways: [],
+    excludedCompartmentPathways: [],
+    models: [],
+    imageFormats: [],
+    imageSize: DEFAULT_IMAGE_SIZE,
+  },
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.context.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.context.ts
index 3490162eb61f13c9ddbf4f2a13d732693e98d003..86f005f09d4dbf9e8ec5643e825c6c0cf33f0486 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.context.ts
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.context.ts
@@ -1,22 +1,5 @@
 import { createContext } from 'react';
-import { CheckboxItem } from '../CheckboxFilter/CheckboxFilter.component';
+import { EXPORT_CONTEXT_DEFAULT_VALUE } from './ExportCompound.constant';
+import { ExportContextType } from './ExportCompound.types';
 
-export type ExportContextType = {
-  setTypes: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
-  setColumns: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
-  setAnnotations: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
-  setIncludedCompartmentPathways: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
-  setExcludedCompartmentPathways: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
-  handleDownloadElements: () => void;
-  handleDownloadNetwork: () => void;
-};
-
-export const ExportContext = createContext<ExportContextType>({
-  setTypes: () => {},
-  setColumns: () => {},
-  setAnnotations: () => {},
-  setIncludedCompartmentPathways: () => {},
-  setExcludedCompartmentPathways: () => {},
-  handleDownloadElements: () => {},
-  handleDownloadNetwork: () => {},
-});
+export const ExportContext = createContext<ExportContextType>(EXPORT_CONTEXT_DEFAULT_VALUE);
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.types.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b6e70397e6d6edb1ca1a5220aebb814c3518ff4e
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.types.ts
@@ -0,0 +1,22 @@
+import { CheckboxItem } from '../CheckboxFilter/CheckboxFilter.types';
+import { ImageSize } from './ImageSize/ImageSize.types';
+
+export type ExportContextType = {
+  setAnnotations: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
+  setIncludedCompartmentPathways: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
+  setExcludedCompartmentPathways: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
+  setModels: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
+  setImageSize: React.Dispatch<React.SetStateAction<ImageSize>>;
+  setImageFormats: React.Dispatch<React.SetStateAction<CheckboxItem[]>>;
+  handleDownloadElements: () => void;
+  handleDownloadNetwork: () => void;
+  handleDownloadGraphics: () => void;
+  data: {
+    annotations: CheckboxItem[];
+    includedCompartmentPathways: CheckboxItem[];
+    excludedCompartmentPathways: CheckboxItem[];
+    models: CheckboxItem[];
+    imageSize: ImageSize;
+    imageFormats: CheckboxItem[];
+  };
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageFormat/ImageFormat.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageFormat/ImageFormat.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..e8c6df3921c6a70d96caeb543b922cd4e6de6ac8
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageFormat/ImageFormat.component.test.tsx
@@ -0,0 +1,131 @@
+import { configurationFixture } from '@/models/fixtures/configurationFixture';
+import {
+  CONFIGURATION_IMAGE_FORMATS_MOCK,
+  CONFIGURATION_IMAGE_FORMATS_TYPES_MOCK,
+} from '@/models/mocks/configurationFormatsMock';
+import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
+import { StoreType } from '@/redux/store';
+import { InitialStoreState } from '@/utils/testing/getReduxStoreActionsListener';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { act, render, screen, waitFor } from '@testing-library/react';
+import { ImageFormat } from './ImageFormat.component';
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <ImageFormat />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('ImageFormat - component', () => {
+  it('should display formats checkboxes when fetching data is successful', async () => {
+    renderComponent({
+      configuration: {
+        ...INITIAL_STORE_STATE_MOCK.configuration,
+        main: {
+          ...INITIAL_STORE_STATE_MOCK.configuration.main,
+          data: {
+            ...configurationFixture,
+            imageFormats: CONFIGURATION_IMAGE_FORMATS_MOCK,
+          },
+        },
+      },
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeVisible();
+
+    const navigationButton = screen.getByTestId('accordion-item-button');
+
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.getByText('Image format')).toBeInTheDocument();
+
+    await waitFor(() => {
+      expect(screen.getByTestId('checkbox-filter')).toBeInTheDocument();
+
+      CONFIGURATION_IMAGE_FORMATS_TYPES_MOCK.map(formatName =>
+        expect(screen.getByLabelText(formatName)).toBeInTheDocument(),
+      );
+    });
+  });
+
+  it('should not display formats checkboxes when fetching data fails', async () => {
+    renderComponent({
+      configuration: {
+        ...INITIAL_STORE_STATE_MOCK.configuration,
+        main: {
+          ...INITIAL_STORE_STATE_MOCK.configuration.main,
+          loading: 'failed',
+        },
+      },
+    });
+
+    expect(screen.getByText('Image format')).toBeInTheDocument();
+
+    const navigationButton = screen.getByTestId('accordion-item-button');
+
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument();
+  });
+
+  it('should not display formats checkboxes when fetched data is empty', async () => {
+    renderComponent({
+      configuration: {
+        ...INITIAL_STORE_STATE_MOCK.configuration,
+        main: {
+          ...INITIAL_STORE_STATE_MOCK.configuration.main,
+          data: {
+            ...configurationFixture,
+            modelFormats: [],
+            imageFormats: [],
+          },
+        },
+      },
+    });
+
+    expect(screen.getByText('Image format')).toBeInTheDocument();
+
+    const navigationButton = screen.getByTestId('accordion-item-button');
+
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument();
+  });
+
+  it('should display loading message when fetching data is pending', async () => {
+    renderComponent({
+      configuration: {
+        ...INITIAL_STORE_STATE_MOCK.configuration,
+        main: {
+          ...INITIAL_STORE_STATE_MOCK.configuration.main,
+          loading: 'pending',
+        },
+      },
+    });
+
+    expect(screen.getByText('Image format')).toBeInTheDocument();
+
+    const navigationButton = screen.getByTestId('accordion-item-button');
+
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.getByText('Loading...')).toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageFormat/ImageFormat.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageFormat/ImageFormat.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..48ab881789d2445fc5f67e5f6a7ffc6c0b7c85e1
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageFormat/ImageFormat.component.tsx
@@ -0,0 +1,40 @@
+import { ZERO } from '@/constants/common';
+import {
+  imageHandlersSelector,
+  loadingConfigurationMainSelector,
+} from '@/redux/configuration/configuration.selectors';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { useContext } from 'react';
+import { CheckboxFilter } from '../../CheckboxFilter';
+import { CollapsibleSection } from '../../CollapsibleSection';
+import { ExportContext } from '../ExportCompound.context';
+
+export const ImageFormat = (): React.ReactNode => {
+  const { setImageFormats, data } = useContext(ExportContext);
+  const currentImageFormats = data.imageFormats;
+  const imageHandlers = useAppSelector(imageHandlersSelector);
+  const loadingConfigurationMain = useAppSelector(loadingConfigurationMainSelector);
+  const isPending = loadingConfigurationMain === 'pending';
+
+  const mappedElementAnnotations = Object.entries(imageHandlers)
+    .filter(([, handler]) => Boolean(handler))
+    .map(([name, handler]) => ({
+      id: handler,
+      label: name,
+    }));
+
+  return (
+    <CollapsibleSection title="Image format">
+      {isPending && <p>Loading...</p>}
+      {!isPending && mappedElementAnnotations.length > ZERO && (
+        <CheckboxFilter
+          options={mappedElementAnnotations}
+          currentOptions={currentImageFormats}
+          onCheckedChange={setImageFormats}
+          type="radio"
+          isSearchEnabled={false}
+        />
+      )}
+    </CollapsibleSection>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageFormat/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageFormat/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d4a3f82e0b569abf113ad6cd986ec01895009a2c
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageFormat/index.ts
@@ -0,0 +1 @@
+export { ImageFormat } from './ImageFormat.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..8affdcd88d2778baffcfd7932cb46c13b3784dc7
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.component.test.tsx
@@ -0,0 +1,151 @@
+/* eslint-disable no-magic-numbers */
+import { StoreType } from '@/redux/store';
+import { InitialStoreState } from '@/utils/testing/getReduxStoreActionsListener';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { fireEvent, render, screen } from '@testing-library/react';
+import { Export } from '../ExportCompound.component';
+import { ImageSize } from './ImageSize.component';
+import { ImageSize as ImageSizeType } from './ImageSize.types';
+
+const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStore);
+
+  return (
+    render(
+      <Wrapper>
+        <Export>
+          <ImageSize />
+        </Export>
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('ImageSize - component', () => {
+  describe('width input', () => {
+    it('renders input with valid value', () => {
+      renderComponent();
+
+      const widthInput: HTMLInputElement = screen.getByLabelText('export graphics width input');
+      expect(widthInput).toBeInTheDocument();
+      expect(widthInput.value).toBe('600');
+    });
+
+    // MAX_WIDTH 600
+    // MAX_HEIGHT 200
+    const widthCases: [number, ImageSizeType][] = [
+      [
+        // default
+        600,
+        {
+          width: 600,
+          height: 200,
+        },
+      ],
+      [
+        // aspect ratio test
+        100,
+        {
+          width: 100,
+          height: 33,
+        },
+      ],
+      [
+        // transform to integer
+        120.2137,
+        {
+          width: 120,
+          height: 40,
+        },
+      ],
+      [
+        // max width
+        997,
+        {
+          width: 600,
+          height: 200,
+        },
+      ],
+    ];
+
+    it.each(widthCases)(
+      'handles input events by setting correct values',
+      async (newWidth, newImageSize) => {
+        renderComponent();
+
+        const widthInput: HTMLInputElement = screen.getByLabelText('export graphics width input');
+        const heightInput: HTMLInputElement = screen.getByLabelText('export graphics height input');
+
+        fireEvent.change(widthInput, { target: { value: `${newWidth}` } });
+
+        expect(widthInput).toHaveValue(newImageSize.width);
+        expect(heightInput).toHaveValue(newImageSize.height);
+      },
+    );
+  });
+
+  describe('height input', () => {
+    it('renders input', () => {
+      renderComponent();
+
+      const heightInput: HTMLInputElement = screen.getByLabelText('export graphics height input');
+      expect(heightInput).toBeInTheDocument();
+      expect(heightInput.value).toBe('200');
+    });
+
+    // MAX_WIDTH 600
+    // MAX_HEIGHT 200
+    const heightCases: [number, ImageSizeType][] = [
+      [
+        // default
+        200,
+        {
+          width: 600,
+          height: 200,
+        },
+      ],
+      [
+        // aspect ratio test
+        100,
+        {
+          width: 300,
+          height: 100,
+        },
+      ],
+      [
+        // transform to integer
+        120.2137,
+        {
+          width: 361,
+          height: 120,
+        },
+      ],
+      [
+        // max height
+        997,
+        {
+          width: 600,
+          height: 200,
+        },
+      ],
+    ];
+
+    it.each(heightCases)(
+      'handles input events by setting correct values',
+      async (newHeight, newImageSize) => {
+        renderComponent();
+
+        const widthInput: HTMLInputElement = screen.getByLabelText('export graphics width input');
+        const heightInput: HTMLInputElement = screen.getByLabelText('export graphics height input');
+
+        fireEvent.change(heightInput, { target: { value: `${newHeight}` } });
+
+        expect(widthInput).toHaveValue(newImageSize.width);
+        expect(heightInput).toHaveValue(newImageSize.height);
+      },
+    );
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..1a66c44e45e0895fb78380222618fa74666cb59b
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.component.tsx
@@ -0,0 +1,37 @@
+import { CollapsibleSection } from '../../CollapsibleSection';
+import { useImageSize } from './utils/useImageSize';
+
+export const ImageSize = (): React.ReactNode => {
+  const { width, height, handleChangeHeight, handleChangeWidth } = useImageSize();
+
+  return (
+    <CollapsibleSection title="Image size">
+      <div className="flex flex-col gap-4">
+        <label className="flex h-9 items-center gap-4">
+          <span className="w-12">Width:&nbsp;</span>
+          <input
+            className="w-full rounded-[64px] border border-transparent bg-cultured px-4 py-2.5 text-xs font-medium text-font-400 outline-none  hover:border-greyscale-600 focus:border-greyscale-600"
+            name="width"
+            value={width}
+            type="number"
+            aria-label="export graphics width input"
+            onChange={(e): void => {
+              handleChangeWidth(Number(e.target.value));
+            }}
+          />
+        </label>
+        <label className="flex h-9 items-center gap-4">
+          <span className="w-12">Height:&nbsp;</span>
+          <input
+            className="w-full rounded-[64px] border border-transparent bg-cultured px-4 py-2.5 text-xs font-medium text-font-400 outline-none  hover:border-greyscale-600 focus:border-greyscale-600"
+            name="height"
+            value={height}
+            type="number"
+            aria-label="export graphics height input"
+            onChange={(e): void => handleChangeHeight(Number(e.target.value))}
+          />
+        </label>
+      </div>
+    </CollapsibleSection>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.constants.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c60ea1d751868d12d199b243da2087c828975739
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.constants.ts
@@ -0,0 +1,14 @@
+import { ImageSize, ModelAspectRatios } from './ImageSize.types';
+
+export const DEFAULT_IMAGE_WIDTH = 600;
+export const DEFAULT_IMAGE_HEIGHT = 200;
+
+export const DEFAULT_IMAGE_SIZE: ImageSize = {
+  width: DEFAULT_IMAGE_WIDTH,
+  height: DEFAULT_IMAGE_HEIGHT,
+};
+
+export const DEFAULT_MODEL_ASPECT_RATIOS: ModelAspectRatios = {
+  vertical: DEFAULT_IMAGE_HEIGHT / DEFAULT_IMAGE_WIDTH,
+  horizontal: DEFAULT_IMAGE_WIDTH / DEFAULT_IMAGE_HEIGHT,
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.types.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a27bad68532fa7cf1974c9ef3892bffb0812fa12
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/ImageSize.types.ts
@@ -0,0 +1,9 @@
+export interface ImageSize {
+  width: number;
+  height: number;
+}
+
+export interface ModelAspectRatios {
+  vertical: number;
+  horizontal: number;
+}
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..42d58d9a6d287540e3888c4532f2a7eaf008552a
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/index.ts
@@ -0,0 +1 @@
+export { ImageSize } from './ImageSize.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useExportGraphicsSelectedModel.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useExportGraphicsSelectedModel.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..20ac3edf4839feec27757384638b0323ad8d4ace
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useExportGraphicsSelectedModel.test.tsx
@@ -0,0 +1,98 @@
+import { FIRST_ARRAY_ELEMENT } from '@/constants/common';
+import { MODELS_MOCK_SHORT } from '@/models/mocks/modelsMock';
+import { renderHook } from '@testing-library/react';
+import { EXPORT_CONTEXT_DEFAULT_VALUE } from '../../ExportCompound.constant';
+import { getExportContextWithReduxWrapper } from '../../utils/getExportContextWithReduxWrapper';
+import { useExportGraphicsSelectedModel } from './useExportGraphicsSelectedModel';
+
+describe('useExportGraphicsSelectedModel - util', () => {
+  describe('when current selected models is empty', () => {
+    const { Wrapper } = getExportContextWithReduxWrapper(
+      {
+        ...EXPORT_CONTEXT_DEFAULT_VALUE,
+        data: {
+          ...EXPORT_CONTEXT_DEFAULT_VALUE.data,
+          models: [],
+        },
+      },
+      {
+        models: {
+          data: [],
+          loading: 'succeeded',
+          error: { name: '', message: '' },
+        },
+      },
+    );
+
+    const { result } = renderHook(() => useExportGraphicsSelectedModel(), {
+      wrapper: Wrapper,
+    });
+
+    it('should return undefined', () => {
+      expect(result.current).toBeUndefined();
+    });
+  });
+
+  describe('when current selected models has one element', () => {
+    describe('when redux models has selected model', () => {
+      const selectedModel = MODELS_MOCK_SHORT[FIRST_ARRAY_ELEMENT];
+
+      const { Wrapper } = getExportContextWithReduxWrapper(
+        {
+          ...EXPORT_CONTEXT_DEFAULT_VALUE,
+          data: {
+            ...EXPORT_CONTEXT_DEFAULT_VALUE.data,
+            models: [
+              {
+                id: selectedModel.idObject.toString(),
+                label: selectedModel.name,
+              },
+            ],
+          },
+        },
+        {
+          models: {
+            data: MODELS_MOCK_SHORT,
+            loading: 'succeeded',
+            error: { name: '', message: '' },
+          },
+        },
+      );
+
+      const { result } = renderHook(() => useExportGraphicsSelectedModel(), {
+        wrapper: Wrapper,
+      });
+
+      it('should return valid model from redux', () => {
+        expect(result.current).toEqual(selectedModel);
+      });
+    });
+
+    describe('when redux models has not selected model', () => {
+      const { Wrapper } = getExportContextWithReduxWrapper(
+        {
+          ...EXPORT_CONTEXT_DEFAULT_VALUE,
+          data: {
+            ...EXPORT_CONTEXT_DEFAULT_VALUE.data,
+            models: [],
+          },
+        },
+        {
+          models: {
+            data: MODELS_MOCK_SHORT,
+            loading: 'succeeded',
+            error: { name: '', message: '' },
+          },
+        },
+      );
+
+      const { result } = renderHook(() => useExportGraphicsSelectedModel(), {
+        wrapper: Wrapper,
+      });
+
+      it('should return undefined', () => {
+        expect(result.current).toBeUndefined();
+      });
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useExportGraphicsSelectedModel.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useExportGraphicsSelectedModel.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5ee35b4c5e7f3f698e20bcc2563ca9883ec21212
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useExportGraphicsSelectedModel.ts
@@ -0,0 +1,18 @@
+import { FIRST_ARRAY_ELEMENT } from '@/constants/common';
+import { modelsDataSelector } from '@/redux/models/models.selectors';
+import { MapModel } from '@/types/models';
+import { useContext } from 'react';
+import { useSelector } from 'react-redux';
+import { ExportContext } from '../../ExportCompound.context';
+
+export const useExportGraphicsSelectedModel = (): MapModel | undefined => {
+  const { data } = useContext(ExportContext);
+  const currentSelectedModelId = data.models?.[FIRST_ARRAY_ELEMENT]?.id;
+  const models = useSelector(modelsDataSelector);
+
+  if (!currentSelectedModelId) {
+    return undefined;
+  }
+
+  return models.find(model => model.idObject === Number(currentSelectedModelId));
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useImageSize.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useImageSize.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a182496ec28a34e4a70556cf03a87ac885a16b83
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useImageSize.test.ts
@@ -0,0 +1,230 @@
+/* eslint-disable no-magic-numbers */
+import { FIRST_ARRAY_ELEMENT } from '@/constants/common';
+import { MODELS_MOCK_SHORT } from '@/models/mocks/modelsMock';
+import { renderHook } from '@testing-library/react';
+import { EXPORT_CONTEXT_DEFAULT_VALUE } from '../../ExportCompound.constant';
+import { getExportContextWithReduxWrapper } from '../../utils/getExportContextWithReduxWrapper';
+import { DEFAULT_IMAGE_SIZE } from '../ImageSize.constants';
+import { ImageSize } from '../ImageSize.types';
+import { useImageSize } from './useImageSize';
+
+describe('useImageSize - hook', () => {
+  describe('when there is no selected model', () => {
+    const { Wrapper } = getExportContextWithReduxWrapper(
+      {
+        ...EXPORT_CONTEXT_DEFAULT_VALUE,
+        data: {
+          ...EXPORT_CONTEXT_DEFAULT_VALUE.data,
+          models: [],
+        },
+      },
+      {
+        models: {
+          data: [],
+          loading: 'succeeded',
+          error: { name: '', message: '' },
+        },
+      },
+    );
+
+    const { result } = renderHook(() => useImageSize(), {
+      wrapper: Wrapper,
+    });
+
+    it('should should return default image size', () => {
+      const { width, height } = result.current || {};
+      expect({ width, height }).toEqual(DEFAULT_IMAGE_SIZE);
+    });
+  });
+
+  describe('when there is a selected model', () => {
+    const selectedModel = MODELS_MOCK_SHORT[FIRST_ARRAY_ELEMENT];
+    const setImageSize = jest.fn();
+
+    const { Wrapper } = getExportContextWithReduxWrapper(
+      {
+        ...EXPORT_CONTEXT_DEFAULT_VALUE,
+        setImageSize,
+        data: {
+          ...EXPORT_CONTEXT_DEFAULT_VALUE.data,
+          models: [
+            {
+              id: selectedModel.idObject.toString(),
+              label: selectedModel.name,
+            },
+          ],
+          imageSize: DEFAULT_IMAGE_SIZE,
+        },
+      },
+      {
+        models: {
+          data: MODELS_MOCK_SHORT,
+          loading: 'succeeded',
+          error: { name: '', message: '' },
+        },
+      },
+    );
+
+    renderHook(() => useImageSize(), {
+      wrapper: Wrapper,
+    });
+
+    it('should should set size of selected model', () => {
+      expect(setImageSize).toHaveBeenCalledWith({
+        width: 26779,
+        height: 13503,
+      });
+    });
+  });
+
+  describe('when always', () => {
+    describe('handleChangeHeight', () => {
+      const selectedModel = MODELS_MOCK_SHORT[FIRST_ARRAY_ELEMENT];
+      const setImageSize = jest.fn();
+
+      const { Wrapper } = getExportContextWithReduxWrapper(
+        {
+          ...EXPORT_CONTEXT_DEFAULT_VALUE,
+          setImageSize,
+          data: {
+            ...EXPORT_CONTEXT_DEFAULT_VALUE.data,
+            models: [
+              {
+                id: selectedModel.idObject.toString(),
+                label: selectedModel.name,
+              },
+            ],
+            imageSize: DEFAULT_IMAGE_SIZE,
+          },
+        },
+        {
+          models: {
+            data: MODELS_MOCK_SHORT,
+            loading: 'succeeded',
+            error: { name: '', message: '' },
+          },
+        },
+      );
+
+      const {
+        result: {
+          current: { handleChangeHeight },
+        },
+      } = renderHook(() => useImageSize(), {
+        wrapper: Wrapper,
+      });
+
+      // MAX_WIDTH 26779.25
+      // MAX_HEIGHT 13503.0
+
+      const heightCases: [number, ImageSize][] = [
+        [
+          // aspect ratio test
+          1000,
+          {
+            width: 1983,
+            height: 1000,
+          },
+        ],
+        [
+          // transform to integer
+          997.2137,
+          {
+            width: 1978,
+            height: 997,
+          },
+        ],
+        [
+          // max height
+          26779000,
+          {
+            width: 26779,
+            height: 13503,
+          },
+        ],
+      ];
+
+      it.each(heightCases)(
+        'should set valid height and width values',
+        (newHeight, newImageSize) => {
+          handleChangeHeight(newHeight);
+
+          expect(setImageSize).toHaveBeenLastCalledWith(newImageSize);
+        },
+      );
+    });
+
+    describe('handleChangeWidth', () => {
+      const selectedModel = MODELS_MOCK_SHORT[FIRST_ARRAY_ELEMENT];
+      const setImageSize = jest.fn();
+
+      const { Wrapper } = getExportContextWithReduxWrapper(
+        {
+          ...EXPORT_CONTEXT_DEFAULT_VALUE,
+          setImageSize,
+          data: {
+            ...EXPORT_CONTEXT_DEFAULT_VALUE.data,
+            models: [
+              {
+                id: selectedModel.idObject.toString(),
+                label: selectedModel.name,
+              },
+            ],
+            imageSize: DEFAULT_IMAGE_SIZE,
+          },
+        },
+        {
+          models: {
+            data: MODELS_MOCK_SHORT,
+            loading: 'succeeded',
+            error: { name: '', message: '' },
+          },
+        },
+      );
+
+      const {
+        result: {
+          current: { handleChangeWidth },
+        },
+      } = renderHook(() => useImageSize(), {
+        wrapper: Wrapper,
+      });
+
+      // MAX_WIDTH 26779.25
+      // MAX_HEIGHT 13503.0
+
+      const widthCases: [number, ImageSize][] = [
+        [
+          // aspect ratio test
+          1000,
+          {
+            width: 1000,
+            height: 504,
+          },
+        ],
+        [
+          // transform to integer
+          997.2137,
+          {
+            width: 997,
+            height: 503,
+          },
+        ],
+        [
+          // max width
+          26779000,
+          {
+            width: 26779,
+            height: 13503,
+          },
+        ],
+      ];
+
+      it.each(widthCases)('should set valid height and width values', (newWidth, newImageSize) => {
+        handleChangeWidth(newWidth);
+
+        expect(setImageSize).toHaveBeenLastCalledWith(newImageSize);
+      });
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useImageSize.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useImageSize.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f36afdd3864b7a7d284103b19c6da8c8641f20d3
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useImageSize.ts
@@ -0,0 +1,88 @@
+import { MapModel } from '@/types/models';
+import { numberToSafeInt } from '@/utils/number/numberToInt';
+import { useCallback, useContext, useEffect } from 'react';
+import { ExportContext } from '../../ExportCompound.context';
+import { DEFAULT_IMAGE_HEIGHT, DEFAULT_IMAGE_WIDTH } from '../ImageSize.constants';
+import { ImageSize } from '../ImageSize.types';
+import { useExportGraphicsSelectedModel } from './useExportGraphicsSelectedModel';
+import { getModelAspectRatios } from './useModelAspectRatios';
+
+interface UseImageSizeResults {
+  handleChangeWidth(width: number): void;
+  handleChangeHeight(height: number): void;
+  width: number;
+  height: number;
+}
+
+export const useImageSize = (): UseImageSizeResults => {
+  const selectedModel = useExportGraphicsSelectedModel();
+  const aspectRatios = getModelAspectRatios(selectedModel);
+  const { data, setImageSize } = useContext(ExportContext);
+  const { imageSize } = data;
+  const maxWidth = selectedModel?.width || DEFAULT_IMAGE_WIDTH;
+  const maxHeight = selectedModel?.height || DEFAULT_IMAGE_HEIGHT;
+
+  const getNormalizedImageSize = useCallback(
+    (newImageSize: ImageSize): ImageSize => {
+      const newWidth = newImageSize.width;
+      const newHeight = newImageSize.height;
+
+      const widthMinMax = Math.min(maxWidth, newWidth);
+      const heightMinMax = Math.min(maxHeight, newHeight);
+
+      const widthInt = numberToSafeInt(widthMinMax);
+      const heightInt = numberToSafeInt(heightMinMax);
+
+      return {
+        width: widthInt,
+        height: heightInt,
+      };
+    },
+    [maxWidth, maxHeight],
+  );
+
+  const setDefaultModelImageSize = useCallback(
+    (model: MapModel): void => {
+      const newImageSize = getNormalizedImageSize({
+        width: model.width,
+        height: model.height,
+      });
+
+      setImageSize(newImageSize);
+    },
+    [getNormalizedImageSize, setImageSize],
+  );
+
+  const handleChangeWidth = (width: number): void => {
+    const newImageSize = getNormalizedImageSize({
+      width,
+      height: width / aspectRatios.horizontal,
+    });
+
+    setImageSize(newImageSize);
+  };
+
+  const handleChangeHeight = (height: number): void => {
+    const newImageSize = getNormalizedImageSize({
+      height,
+      width: height / aspectRatios.vertical,
+    });
+
+    setImageSize(newImageSize);
+  };
+
+  useEffect(() => {
+    if (!selectedModel) {
+      return;
+    }
+
+    setDefaultModelImageSize(selectedModel);
+  }, [setDefaultModelImageSize, selectedModel]);
+
+  return {
+    handleChangeWidth,
+    handleChangeHeight,
+    width: imageSize.width,
+    height: imageSize.height,
+  };
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useModelAspectRatios.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useModelAspectRatios.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..42468de1d2911fb6f17ccca659874d892eaf7ab3
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useModelAspectRatios.test.ts
@@ -0,0 +1,45 @@
+import { MapModel } from '@/types/models';
+import { DEFAULT_MODEL_ASPECT_RATIOS } from '../ImageSize.constants';
+import { ModelAspectRatios } from '../ImageSize.types';
+import { getModelAspectRatios } from './useModelAspectRatios';
+
+describe('useModelAspectRatios - hook', () => {
+  describe('when model is not present', () => {
+    const model = undefined;
+
+    it('should return default model aspect ratio', () => {
+      const result = getModelAspectRatios(model);
+      expect(result).toEqual(DEFAULT_MODEL_ASPECT_RATIOS);
+    });
+  });
+
+  describe('when model is present', () => {
+    const modelCases: [Pick<MapModel, 'width' | 'height'>, ModelAspectRatios][] = [
+      [
+        {
+          width: 1000,
+          height: 500,
+        },
+        {
+          vertical: 0.5,
+          horizontal: 2,
+        },
+      ],
+      [
+        {
+          width: 4200,
+          height: 420,
+        },
+        {
+          vertical: 0.1,
+          horizontal: 10,
+        },
+      ],
+    ];
+
+    it.each(modelCases)('should return valid model aspect ratio', (model, expectedResult) => {
+      const result = getModelAspectRatios(model);
+      expect(result).toEqual(expectedResult);
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useModelAspectRatios.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useModelAspectRatios.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c4f23862eac2349a5f2e74ca217e03a06806d320
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ImageSize/utils/useModelAspectRatios.ts
@@ -0,0 +1,16 @@
+import { MapModel } from '@/types/models';
+import { DEFAULT_MODEL_ASPECT_RATIOS } from '../ImageSize.constants';
+import { ModelAspectRatios } from '../ImageSize.types';
+
+export const getModelAspectRatios = (
+  model: Pick<MapModel, 'width' | 'height'> | undefined,
+): ModelAspectRatios => {
+  if (!model) {
+    return DEFAULT_MODEL_ASPECT_RATIOS;
+  }
+
+  return {
+    vertical: model.height / model.width,
+    horizontal: model.width / model.height,
+  };
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx
index 39164e58904ff7d2667b9573c82ad1d5a38e58f1..4ef2cee4762cb803993095517e88c929323e056d 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx	
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx	
@@ -1,21 +1,22 @@
-import { useContext } from 'react';
+import { ZERO } from '@/constants/common';
 import {
   compartmentPathwaysDataSelector,
   loadingCompartmentPathwaysSelector,
 } from '@/redux/compartmentPathways/compartmentPathways.selectors';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
-import { ZERO } from '@/constants/common';
+import { useContext } from 'react';
 import { CheckboxFilter } from '../../CheckboxFilter';
 import { CollapsibleSection } from '../../CollapsibleSection';
 import { ExportContext } from '../ExportCompound.context';
 import { getCompartmentPathwaysCheckboxElements } from '../utils/getCompartmentPathwaysCheckboxElements';
 
 export const IncludedCompartmentPathways = (): React.ReactNode => {
-  const { setIncludedCompartmentPathways } = useContext(ExportContext);
+  const { setIncludedCompartmentPathways, data } = useContext(ExportContext);
+  const currentIncludedCompartmentPathways = data.includedCompartmentPathways;
   const loadingCompartmentPathways = useAppSelector(loadingCompartmentPathwaysSelector);
   const isPending = loadingCompartmentPathways === 'pending';
   const compartmentPathways = useAppSelector(compartmentPathwaysDataSelector);
-  const checkboxElements = getCompartmentPathwaysCheckboxElements(compartmentPathways);
+  const checkboxElements = getCompartmentPathwaysCheckboxElements('included', compartmentPathways);
 
   return (
     <CollapsibleSection title="Select included compartment / pathways">
@@ -23,6 +24,7 @@ export const IncludedCompartmentPathways = (): React.ReactNode => {
       {!isPending && checkboxElements && checkboxElements.length > ZERO && (
         <CheckboxFilter
           options={checkboxElements}
+          currentOptions={currentIncludedCompartmentPathways}
           onCheckedChange={setIncludedCompartmentPathways}
         />
       )}
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..2374285dc947b4e0fa4c66e0ab8384f2ab58571f
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.test.tsx
@@ -0,0 +1,116 @@
+/* eslint-disable no-magic-numbers */
+import { modelsFixture } from '@/models/fixtures/modelsFixture';
+import { StoreType } from '@/redux/store';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { render, screen, waitFor } from '@testing-library/react';
+import { act } from 'react-dom/test-utils';
+import { Submap } from './Submap.component';
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <Submap />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+const CHECKBOX_ELEMENT_NAME = modelsFixture[0].name;
+
+describe('Submap - component', () => {
+  it('should display submaps checkboxes when fetching data is successful', async () => {
+    renderComponent({
+      models: {
+        data: modelsFixture,
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeVisible();
+
+    const navigationButton = screen.getByTestId('accordion-item-button');
+
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.getByText('Submap')).toBeInTheDocument();
+
+    await waitFor(() => {
+      expect(screen.getByTestId('checkbox-filter')).toBeInTheDocument();
+      expect(screen.getByLabelText('search-input')).toBeInTheDocument();
+      expect(screen.getByLabelText(CHECKBOX_ELEMENT_NAME)).toBeInTheDocument();
+    });
+  });
+  it('should not display submaps checkboxes when fetching data fails', async () => {
+    renderComponent({
+      models: {
+        data: [],
+        loading: 'failed',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+    expect(screen.getByText('Submap')).toBeInTheDocument();
+    const navigationButton = screen.getByTestId('accordion-item-button');
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument();
+  });
+  it('should not display submaps checkboxes when fetched data is empty', async () => {
+    renderComponent({
+      models: {
+        data: [],
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+    expect(screen.getByText('Submap')).toBeInTheDocument();
+    const navigationButton = screen.getByTestId('accordion-item-button');
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument();
+  });
+
+  it('should display loading message when fetching data is pending', async () => {
+    renderComponent({
+      models: {
+        data: [],
+        loading: 'pending',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+    expect(screen.getByText('Submap')).toBeInTheDocument();
+    const navigationButton = screen.getByTestId('accordion-item-button');
+    act(() => {
+      navigationButton.click();
+    });
+
+    expect(screen.getByText('Loading...')).toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..5c5590ce5c669473922f966cfdfcc13df4269f77
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/Submap.component.tsx
@@ -0,0 +1,34 @@
+import { ZERO } from '@/constants/common';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { loadingModelsSelector, modelsDataSelector } from '@/redux/models/models.selectors';
+import { useContext } from 'react';
+import { CheckboxFilter } from '../../CheckboxFilter';
+import { CollapsibleSection } from '../../CollapsibleSection';
+import { ExportContext } from '../ExportCompound.context';
+
+export const Submap = (): React.ReactNode => {
+  const { setModels, data } = useContext(ExportContext);
+  const currentSelectedModels = data.models;
+  const models = useAppSelector(modelsDataSelector);
+  const loadingModels = useAppSelector(loadingModelsSelector);
+  const isPending = loadingModels === 'pending';
+
+  const mappedElementAnnotations = models.map(({ idObject, name }) => ({
+    id: `${idObject}`,
+    label: name,
+  }));
+
+  return (
+    <CollapsibleSection title="Submap">
+      {isPending && <p>Loading...</p>}
+      {!isPending && mappedElementAnnotations && mappedElementAnnotations.length > ZERO && (
+        <CheckboxFilter
+          options={mappedElementAnnotations}
+          currentOptions={currentSelectedModels}
+          onCheckedChange={setModels}
+          type="radio"
+        />
+      )}
+    </CollapsibleSection>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..89fa39d0a0caeb34a8012e61e25b2b9fa9a1b7ed
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Submap/index.ts
@@ -0,0 +1 @@
+export { Submap } from './Submap.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.component.test.tsx
deleted file mode 100644
index 4d228509706c27621afef1d5620a23dc03d647ab..0000000000000000000000000000000000000000
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.component.test.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { render, screen } from '@testing-library/react';
-import {
-  InitialStoreState,
-  getReduxWrapperWithStore,
-} from '@/utils/testing/getReduxWrapperWithStore';
-import { StoreType } from '@/redux/store';
-import { Types } from './Types.component';
-
-const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
-  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
-
-  return (
-    render(
-      <Wrapper>
-        <Types />
-      </Wrapper>,
-    ),
-    {
-      store,
-    }
-  );
-};
-
-describe('Types Component', () => {
-  test('renders without crashing', () => {
-    renderComponent();
-    expect(screen.getByText('Select types')).toBeInTheDocument();
-  });
-});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.component.tsx
deleted file mode 100644
index 9398790028d9a1e60cbaeee9bf85014523839570..0000000000000000000000000000000000000000
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.component.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { useContext } from 'react';
-import { elementTypesSelector } from '@/redux/configuration/configuration.selectors';
-import { useAppSelector } from '@/redux/hooks/useAppSelector';
-import { getCheckboxElements } from './Types.utils';
-import { CheckboxFilter } from '../../CheckboxFilter';
-import { CollapsibleSection } from '../../CollapsibleSection';
-import { ExportContext } from '../ExportCompound.context';
-
-export const Types = (): React.ReactNode => {
-  const { setTypes } = useContext(ExportContext);
-  const elementTypes = useAppSelector(elementTypesSelector);
-  const checkboxElements = getCheckboxElements(elementTypes);
-
-  return (
-    <CollapsibleSection title="Select types">
-      {checkboxElements && (
-        <CheckboxFilter
-          options={checkboxElements}
-          isSearchEnabled={false}
-          onCheckedChange={setTypes}
-        />
-      )}
-    </CollapsibleSection>
-  );
-};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.utils.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.utils.test.ts
deleted file mode 100644
index 34e10ae6cf11eba8a045e3929738f636f2a03620..0000000000000000000000000000000000000000
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.utils.test.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { getCheckboxElements } from './Types.utils';
-
-describe('getCheckboxElements', () => {
-  it('should return an empty array when elementTypes is undefined', () => {
-    const result = getCheckboxElements(undefined);
-    expect(result).toEqual([]);
-  });
-
-  it('should map elementTypes to MappedElementTypes and exclude duplicates based on name and parentClass', () => {
-    const elementTypes = [
-      { className: 'class1', name: 'type1', parentClass: 'parent1' },
-      { className: 'class2', name: 'type2', parentClass: 'parent2' },
-      { className: 'class1', name: 'type1', parentClass: 'parent1' },
-      { className: 'class3', name: 'type3', parentClass: 'parent3' },
-      { className: 'class2', name: 'type2', parentClass: 'parent2' },
-    ];
-
-    const result = getCheckboxElements(elementTypes);
-
-    expect(result).toEqual([
-      { id: 'type1', label: 'type1' },
-      { id: 'type2', label: 'type2' },
-      { id: 'type3', label: 'type3' },
-    ]);
-  });
-
-  it('should handle an empty array of elementTypes', () => {
-    const result = getCheckboxElements([]);
-    expect(result).toEqual([]);
-  });
-
-  it('should return an empty array when elementTypes is undefined', () => {
-    const result = getCheckboxElements(undefined);
-    expect(result).toEqual([]);
-  });
-});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.utils.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.utils.ts
deleted file mode 100644
index a8a7cc990d683cad01bd17ca5f8007f4bce4e86b..0000000000000000000000000000000000000000
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/Types.utils.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-type ElementTypes =
-  | {
-      className: string;
-      name: string;
-      parentClass: string;
-    }[]
-  | undefined;
-
-type MappedElementTypes = { id: string; label: string }[];
-
-type PresenceMap = { [key: string]: boolean };
-
-export const getCheckboxElements = (elementTypes: ElementTypes): MappedElementTypes => {
-  if (!elementTypes) return [];
-
-  const excludedTypes: PresenceMap = {};
-  elementTypes?.forEach(type => {
-    excludedTypes[type.parentClass] = true;
-  });
-
-  const mappedElementTypes: MappedElementTypes = [];
-  const processedNames: PresenceMap = {};
-
-  elementTypes.forEach(elementType => {
-    if (excludedTypes[elementType.className] || processedNames[elementType.name]) return;
-
-    processedNames[elementType.name] = true;
-    mappedElementTypes.push({
-      id: elementType.name,
-      label: elementType.name,
-    });
-  });
-
-  return mappedElementTypes;
-};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/index.ts
deleted file mode 100644
index ce8a0cc157c89e6d8b723d3b67d9479b8a1df515..0000000000000000000000000000000000000000
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/Types/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Types } from './Types.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/extractAndParseNumberIdFromCompartment.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/extractAndParseNumberIdFromCompartment.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7ea949afd9f0716a6af6aabdc8d2694fe1490f16
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/extractAndParseNumberIdFromCompartment.test.ts
@@ -0,0 +1,26 @@
+/* eslint-disable no-magic-numbers */
+import { extractAndParseNumberIdFromCompartment } from './extractAndParseNumberIdFromCompartment';
+
+describe('extractAndParseNumberIdFromCompartment', () => {
+  it('should extract and parse number id from compartment', () => {
+    const compartment = { id: 'compartment-123', label: 'x' };
+    const result = extractAndParseNumberIdFromCompartment(compartment);
+    expect(result).toBe(123);
+  });
+
+  it('should handle id with non-numeric characters', () => {
+    const compartment = { id: 'compartment-abc', label: 'x' };
+
+    expect(() => extractAndParseNumberIdFromCompartment(compartment)).toThrowError(
+      'compartment id is not a number',
+    );
+  });
+
+  it('should handle missing id', () => {
+    const compartment = { id: 'compartment-', label: 'x' };
+
+    expect(() => extractAndParseNumberIdFromCompartment(compartment)).toThrowError(
+      'compartment id is not a number',
+    );
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/extractAndParseNumberIdFromCompartment.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/extractAndParseNumberIdFromCompartment.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e0cc82546fda54de629e92dbf24fa4e68d41de0e
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/extractAndParseNumberIdFromCompartment.ts
@@ -0,0 +1,10 @@
+import { CheckboxItem } from '../../CheckboxFilter/CheckboxFilter.types';
+
+export const extractAndParseNumberIdFromCompartment = (compartment: CheckboxItem): number => {
+  const [, id] = compartment.id.split('-');
+  const numberId = Number(id);
+
+  if (Number.isNaN(numberId) || id === '') throw new Error('compartment id is not a number');
+
+  return numberId;
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.test.ts
index d0a7806ce4d62ea5210b1249087b97345affa819..6254cd6bd795c47606f394660040e720e61983ea 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.test.ts
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.test.ts
@@ -5,7 +5,7 @@ import { getCompartmentPathwaysCheckboxElements } from './getCompartmentPathways
 describe('getCompartmentPathwaysCheckboxElements', () => {
   it('should return an empty array when given an empty items array', () => {
     const items: CompartmentPathwayDetails[] = [];
-    const result = getCompartmentPathwaysCheckboxElements(items);
+    const result = getCompartmentPathwaysCheckboxElements('include', items);
     expect(result).toEqual([]);
   });
 
@@ -17,12 +17,12 @@ describe('getCompartmentPathwaysCheckboxElements', () => {
       { id: 4, name: 'Compartment C' },
     ] as CompartmentPathwayDetails[];
 
-    const result = getCompartmentPathwaysCheckboxElements(items);
+    const result = getCompartmentPathwaysCheckboxElements('test', items);
 
     expect(result).toEqual([
-      { id: '1', label: 'Compartment A' },
-      { id: '2', label: 'Compartment B' },
-      { id: '4', label: 'Compartment C' },
+      { id: 'test-1', label: 'Compartment A' },
+      { id: 'test-2', label: 'Compartment B' },
+      { id: 'test-4', label: 'Compartment C' },
     ]);
   });
   it('should correctly extract unique names and corresponding ids from items and sorts them alphabetically', () => {
@@ -34,13 +34,13 @@ describe('getCompartmentPathwaysCheckboxElements', () => {
       { id: 5, name: 'Compartment D' },
     ] as CompartmentPathwayDetails[];
 
-    const result = getCompartmentPathwaysCheckboxElements(items);
+    const result = getCompartmentPathwaysCheckboxElements('prefix', items);
 
     expect(result).toEqual([
-      { id: '2', label: 'Compartment A' },
-      { id: '3', label: 'Compartment B' },
-      { id: '1', label: 'Compartment C' },
-      { id: '5', label: 'Compartment D' },
+      { id: 'prefix-2', label: 'Compartment A' },
+      { id: 'prefix-3', label: 'Compartment B' },
+      { id: 'prefix-1', label: 'Compartment C' },
+      { id: 'prefix-5', label: 'Compartment D' },
     ]);
   });
 });
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.ts
index e0f4bf81a14c4fece41eff986e4b3685b2506f16..9a807f04e97bc26296e9a4922fd312637bb7e54e 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.ts
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getCompartmentPathwaysCheckboxElements.ts
@@ -8,6 +8,7 @@ type CheckboxElement = { id: string; label: string };
 type CheckboxElements = CheckboxElement[];
 
 export const getCompartmentPathwaysCheckboxElements = (
+  prefix: string,
   items: CompartmentPathwayDetails[],
 ): CheckboxElements => {
   const addedNames: AddedNames = {};
@@ -21,7 +22,7 @@ export const getCompartmentPathwaysCheckboxElements = (
   items.forEach(setNameToIdIfUndefined);
 
   const parseIdAndLabel = ([name, id]: [name: string, id: number]): CheckboxElement => ({
-    id: id.toString(),
+    id: `${prefix}-${id}`,
     label: name,
   });
 
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.test.ts
index 68d1e8f0ae0858439f4ed21fc681eef713d921b1..6e9dbdac7995fcc6aa82867abf9e5ee6ec6c6546 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.test.ts
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.test.ts
@@ -1,33 +1,25 @@
+/* eslint-disable no-magic-numbers */
 import { getDownloadElementsBodyRequest } from './getDownloadElementsBodyRequest';
 
 describe('getDownloadElementsBodyRequest', () => {
   it('should return the correct DownloadBodyRequest object', () => {
-    const types = [
-      { id: '1', label: 'Type 1' },
-      { id: '2', label: 'Type 2' },
-    ];
-    const columns = [
-      { id: '1', label: 'Column 1' },
-      { id: '2', label: 'Column 2' },
-    ];
     // eslint-disable-next-line no-magic-numbers
     const modelIds = [1, 2, 3];
     const annotations = [
-      { id: '1', label: 'Annotation 1' },
-      { id: '2', label: 'Annotation 2' },
+      { id: 'Annotation 1', label: 'Annotation 1' },
+      { id: 'Annotation 2', label: 'Annotation 2' },
     ];
     const includedCompartmentPathways = [
-      { id: '1', label: 'Compartment 1' },
-      { id: '2', label: 'Compartment 2' },
+      { id: 'include-7', label: 'Compartment 1' },
+      { id: 'include-8', label: 'Compartment 2' },
     ];
     const excludedCompartmentPathways = [
-      { id: '1', label: 'Compartment 3' },
-      { id: '2', label: 'Compartment 4' },
+      { id: 'exclude-9', label: 'Compartment 3' },
+      { id: 'exclude-10', label: 'Compartment 4' },
     ];
 
     const result = getDownloadElementsBodyRequest({
-      types,
-      columns,
+      columns: ['Column 23', 'Column99'],
       modelIds,
       annotations,
       includedCompartmentPathways,
@@ -35,13 +27,37 @@ describe('getDownloadElementsBodyRequest', () => {
     });
 
     expect(result).toEqual({
-      types: ['Type 1', 'Type 2'],
-      columns: ['Column 1', 'Column 2'],
+      columns: ['Column 23', 'Column99'],
       // eslint-disable-next-line no-magic-numbers
       submaps: [1, 2, 3],
       annotations: ['Annotation 1', 'Annotation 2'],
-      includedCompartmentIds: ['Compartment 1', 'Compartment 2'],
-      excludedCompartmentIds: ['Compartment 3', 'Compartment 4'],
+      includedCompartmentIds: [7, 8],
+      excludedCompartmentIds: [9, 10],
     });
   });
+  it('should throw error if compartment id is not a number', () => {
+    const modelIds = [1, 2, 3];
+    const annotations = [
+      { id: 'Annotation 1', label: 'Annotation 1' },
+      { id: 'Annotation 2', label: 'Annotation 2' },
+    ];
+    const includedCompartmentPathways = [
+      { id: '', label: 'Compartment 1' },
+      { id: '', label: 'Compartment 2' },
+    ];
+    const excludedCompartmentPathways = [
+      { id: '', label: 'Compartment 3' },
+      { id: '', label: 'Compartment 4' },
+    ];
+
+    expect(() =>
+      getDownloadElementsBodyRequest({
+        columns: ['Column 23', 'Column99'],
+        modelIds,
+        annotations,
+        includedCompartmentPathways,
+        excludedCompartmentPathways,
+      }),
+    ).toThrow('compartment id is not a number');
+  });
 });
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.ts
index 1a262a95703df1efc1e0baba873acf11cc50e13a..6cfb3494a9668d99be8fb6ac5152fa01bd1f5486 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.ts
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getDownloadElementsBodyRequest.ts
@@ -1,17 +1,16 @@
-import { CheckboxItem } from '../../CheckboxFilter/CheckboxFilter.component';
+import { CheckboxItem } from '../../CheckboxFilter/CheckboxFilter.types';
+import { extractAndParseNumberIdFromCompartment } from './extractAndParseNumberIdFromCompartment';
 
 type DownloadBodyRequest = {
-  types: string[];
   columns: string[];
   submaps: number[];
   annotations: string[];
-  includedCompartmentIds: string[];
-  excludedCompartmentIds: string[];
+  includedCompartmentIds: number[];
+  excludedCompartmentIds: number[];
 };
 
 type GetDownloadBodyRequestProps = {
-  types: CheckboxItem[];
-  columns: CheckboxItem[];
+  columns: string[];
   modelIds: number[];
   annotations: CheckboxItem[];
   includedCompartmentPathways: CheckboxItem[];
@@ -19,17 +18,15 @@ type GetDownloadBodyRequestProps = {
 };
 
 export const getDownloadElementsBodyRequest = ({
-  types,
   columns,
   modelIds,
   annotations,
   includedCompartmentPathways,
   excludedCompartmentPathways,
 }: GetDownloadBodyRequestProps): DownloadBodyRequest => ({
-  types: types.map(type => type.label),
-  columns: columns.map(column => column.label),
+  columns,
   submaps: modelIds,
-  annotations: annotations.map(annotation => annotation.label),
-  includedCompartmentIds: includedCompartmentPathways.map(compartment => compartment.label),
-  excludedCompartmentIds: excludedCompartmentPathways.map(compartment => compartment.label),
+  annotations: annotations.map(annotation => annotation.id),
+  includedCompartmentIds: includedCompartmentPathways.map(extractAndParseNumberIdFromCompartment),
+  excludedCompartmentIds: excludedCompartmentPathways.map(extractAndParseNumberIdFromCompartment),
 });
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getExportContextWithReduxWrapper.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getExportContextWithReduxWrapper.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..1d84ad2413c15fac273dbc6995b2dade33ad7928
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getExportContextWithReduxWrapper.tsx
@@ -0,0 +1,46 @@
+/* eslint-disable react/no-multi-comp */
+import { StoreType } from '@/redux/store';
+import { InitialStoreState } from '@/utils/testing/getReduxStoreActionsListener';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { EXPORT_CONTEXT_DEFAULT_VALUE } from '../ExportCompound.constant';
+import { ExportContext } from '../ExportCompound.context';
+import { ExportContextType } from '../ExportCompound.types';
+
+interface WrapperProps {
+  children: React.ReactNode;
+}
+
+export type ComponentWrapper = ({ children }: WrapperProps) => JSX.Element;
+
+export type GetExportContextWithReduxWrapper = (
+  contextValue?: ExportContextType,
+  initialState?: InitialStoreState,
+) => {
+  Wrapper: ComponentWrapper;
+  store: StoreType;
+};
+
+export const getExportContextWithReduxWrapper: GetExportContextWithReduxWrapper = (
+  contextValue,
+  initialState,
+) => {
+  const { Wrapper: ReduxWrapper, store } = getReduxWrapperWithStore(initialState);
+
+  const ContextWrapper: ComponentWrapper = ({ children }) => {
+    return (
+      <ExportContext.Provider value={contextValue || EXPORT_CONTEXT_DEFAULT_VALUE}>
+        {children}
+      </ExportContext.Provider>
+    );
+  };
+
+  const ContextWrapperWithRedux: ComponentWrapper = ({ children }) => {
+    return (
+      <ReduxWrapper>
+        <ContextWrapper>{children}</ContextWrapper>
+      </ReduxWrapper>
+    );
+  };
+
+  return { Wrapper: ContextWrapperWithRedux, store };
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getGraphicsDownloadUrl.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getGraphicsDownloadUrl.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2e6c4db9026bd78b950223fa64e5b3afe5161606
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getGraphicsDownloadUrl.test.ts
@@ -0,0 +1,42 @@
+import { BASE_API_URL, PROJECT_ID } from '@/constants';
+import { GetGraphicsDownloadUrlProps, getGraphicsDownloadUrl } from './getGraphicsDownloadUrl';
+
+describe('getGraphicsDownloadUrl - util', () => {
+  const cases: [GetGraphicsDownloadUrlProps, string | undefined][] = [
+    [{}, undefined],
+    [
+      {
+        backgroundId: 50,
+      },
+      undefined,
+    ],
+    [
+      {
+        backgroundId: 50,
+        modelId: '30',
+      },
+      undefined,
+    ],
+    [
+      {
+        backgroundId: 50,
+        modelId: '30',
+        handler: 'any.handler.image',
+      },
+      undefined,
+    ],
+    [
+      {
+        backgroundId: 50,
+        modelId: '30',
+        handler: 'any.handler.image',
+        zoom: 7,
+      },
+      `${BASE_API_URL}/projects/${PROJECT_ID}/models/30:downloadImage?backgroundOverlayId=50&handlerClass=any.handler.image&zoomLevel=7`,
+    ],
+  ];
+
+  it.each(cases)('should return valid result', (input, result) => {
+    expect(getGraphicsDownloadUrl(input)).toBe(result);
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getGraphicsDownloadUrl.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getGraphicsDownloadUrl.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c4020e9899f75685c7b732db23dd246077d433e7
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getGraphicsDownloadUrl.ts
@@ -0,0 +1,26 @@
+import { BASE_API_URL, PROJECT_ID } from '@/constants';
+
+export interface GetGraphicsDownloadUrlProps {
+  backgroundId?: number;
+  modelId?: string;
+  handler?: string;
+  zoom?: number;
+}
+
+export const getGraphicsDownloadUrl = ({
+  backgroundId,
+  modelId,
+  handler,
+  zoom,
+}: GetGraphicsDownloadUrlProps): string | undefined => {
+  const isAllElementsTruthy = [backgroundId, modelId, handler, zoom].reduce(
+    (a, b) => Boolean(a) && Boolean(b),
+    true,
+  );
+
+  if (!isAllElementsTruthy) {
+    return undefined;
+  }
+
+  return `${BASE_API_URL}/projects/${PROJECT_ID}/models/${modelId}:downloadImage?backgroundOverlayId=${backgroundId}&handlerClass=${handler}&zoomLevel=${zoom}`;
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getModelExportZoom.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getModelExportZoom.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..247ce802c96c25153d55fce4fc07a4eea5bbc431
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getModelExportZoom.test.ts
@@ -0,0 +1,45 @@
+/* eslint-disable no-magic-numbers */
+import { FIRST_ARRAY_ELEMENT, ZERO } from '@/constants/common';
+import { MODELS_MOCK_SHORT } from '@/models/mocks/modelsMock';
+import { getModelExportZoom } from './getModelExportZoom';
+
+describe('getModelExportZoom - util', () => {
+  describe('when there is no model', () => {
+    const model = undefined;
+    const exportWidth = 100;
+
+    it('should return return zero', () => {
+      expect(getModelExportZoom(exportWidth, model)).toBe(ZERO);
+    });
+  });
+
+  // Math.log2 of zero is -Infty
+  describe('when model width is zero', () => {
+    const model = {
+      ...MODELS_MOCK_SHORT[FIRST_ARRAY_ELEMENT],
+      width: 0,
+    };
+    const exportWidth = 100;
+
+    it('should return return zero', () => {
+      expect(getModelExportZoom(exportWidth, model)).toBe(ZERO);
+    });
+  });
+
+  describe('when model is present and model width > ZERO', () => {
+    const model = MODELS_MOCK_SHORT[FIRST_ARRAY_ELEMENT];
+
+    // MAX_WIDTH 26779.25
+    // [zoom, width]
+    const cases: [number, number][] = [
+      [2, 100], // MIN ZOOM
+      [2.7142, 420],
+      [4.5391, 1488],
+      [9, 80000000], // MAX ZOOM
+    ];
+
+    it.each(cases)('should return export zoom=%s for width=%s', (zoom, width) => {
+      expect(getModelExportZoom(width, model)).toBeCloseTo(zoom);
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getModelExportZoom.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getModelExportZoom.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c198def10be36fe02577193626180f285ede6e9b
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getModelExportZoom.ts
@@ -0,0 +1,22 @@
+import { ZERO } from '@/constants/common';
+import { MapModel } from '@/types/models';
+
+const ZOOM_BASE = 6;
+
+/*
+ * Width of exported image for zoom=1 is 128, for zoom=2 is 256, for zoom=3 is 1024
+ * So zoom level holds pattern of log2(width) with base of log2(128)=7
+ * Zoom base defined in this file is 6 as we need to provide minumum zoom of 1
+ */
+
+export const getModelExportZoom = (exportWidth: number, model?: MapModel): number => {
+  // log2 of zero is -Infty
+  if (!model || model.width === ZERO) {
+    return ZERO;
+  }
+
+  const { maxZoom, minZoom } = model;
+  const exportZoom = Math.log2(exportWidth) - ZOOM_BASE;
+
+  return Math.min(Math.max(exportZoom, minZoom), maxZoom);
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.test.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.test.ts
index 1aa3d73b227fb3f5ba7ce6a3fd69e70b161ac58e..42f38d9fa45920846738d08a3aec0e79d6bc1d68 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.test.ts
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.test.ts
@@ -1,8 +1,37 @@
+/* eslint-disable no-magic-numbers */
 import { getNetworkDownloadBodyRequest } from './getNetworkBodyRequest';
 
 describe('getNetworkDownloadBodyRequest', () => {
-  it('should return an empty object', () => {
-    const result = getNetworkDownloadBodyRequest();
-    expect(result).toEqual({});
+  it('should return the correct DownloadBodyRequest object', () => {
+    const columns = ['column1', 'column2'];
+    const modelIds = [1, 2, 3];
+    const annotations = [
+      { id: 'Annotation 1', label: 'Annotation 1' },
+      { id: 'Annotation 2', label: 'Annotation 2' },
+    ];
+    const includedCompartmentPathways = [
+      { id: 'include-7', label: 'Compartment 1' },
+      { id: 'include-8', label: 'Compartment 2' },
+    ];
+    const excludedCompartmentPathways = [
+      { id: 'exclude-9', label: 'Compartment 3' },
+      { id: 'exclude-10', label: 'Compartment 4' },
+    ];
+
+    const result = getNetworkDownloadBodyRequest({
+      columns,
+      modelIds,
+      annotations,
+      includedCompartmentPathways,
+      excludedCompartmentPathways,
+    });
+
+    expect(result).toEqual({
+      columns: ['column1', 'column2'],
+      submaps: [1, 2, 3],
+      annotations: ['Annotation 1', 'Annotation 2'],
+      includedCompartmentIds: [7, 8],
+      excludedCompartmentIds: [9, 10],
+    });
   });
 });
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.ts
index 6613aea72d35cc71d858350896d3d8ea79121e73..eadc0e8c0b9091093d92f3f0b5acf587770b036d 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.ts
+++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/utils/getNetworkBodyRequest.ts
@@ -1 +1,32 @@
-export const getNetworkDownloadBodyRequest = (): object => ({});
+import { CheckboxItem } from '../../CheckboxFilter/CheckboxFilter.types';
+import { extractAndParseNumberIdFromCompartment } from './extractAndParseNumberIdFromCompartment';
+
+type DownloadBodyRequest = {
+  columns: string[];
+  submaps: number[];
+  annotations: string[];
+  includedCompartmentIds: number[];
+  excludedCompartmentIds: number[];
+};
+
+type GetDownloadBodyRequestProps = {
+  columns: string[];
+  modelIds: number[];
+  annotations: CheckboxItem[];
+  includedCompartmentPathways: CheckboxItem[];
+  excludedCompartmentPathways: CheckboxItem[];
+};
+
+export const getNetworkDownloadBodyRequest = ({
+  columns,
+  modelIds,
+  annotations,
+  includedCompartmentPathways,
+  excludedCompartmentPathways,
+}: GetDownloadBodyRequestProps): DownloadBodyRequest => ({
+  columns,
+  submaps: modelIds,
+  annotations: annotations.map(annotation => annotation.id),
+  includedCompartmentIds: includedCompartmentPathways.map(extractAndParseNumberIdFromCompartment),
+  excludedCompartmentIds: excludedCompartmentPathways.map(extractAndParseNumberIdFromCompartment),
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx
index 1d98f663a79aae7c2dbe4b2e954c58c32536794f..408b68c779a1f5a9e488e662ca24c9a3c0120b0a 100644
--- a/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx
+++ b/src/components/Map/Drawer/ExportDrawer/ExportDrawer.component.tsx
@@ -1,14 +1,15 @@
+import { getCompartmentPathways } from '@/redux/compartmentPathways/compartmentPathways.thunks';
 import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import { modelsIdsSelector } from '@/redux/models/models.selectors';
 import { DrawerHeading } from '@/shared/DrawerHeading';
-import { getCompartmentPathways } from '@/redux/compartmentPathways/compartmentPathways.thunks';
 import { useEffect, useState } from 'react';
-import { TabNavigator } from './TabNavigator';
 import { Elements } from './Elements';
+import { Graphics } from './Graphics';
+import { Network } from './Network';
+import { TabNavigator } from './TabNavigator';
 import { TAB_NAMES } from './TabNavigator/TabNavigator.constants';
 import { TabNames } from './TabNavigator/TabNavigator.types';
-import { Network } from './Network';
 
 export const ExportDrawer = (): React.ReactNode => {
   const modelsIds = useAppSelector(modelsIdsSelector);
@@ -30,7 +31,7 @@ export const ExportDrawer = (): React.ReactNode => {
         <TabNavigator activeTab={activeTab} onTabChange={handleTabChange} />
         {activeTab === TAB_NAMES.ELEMENTS && <Elements />}
         {activeTab === TAB_NAMES.NETWORK && <Network />}
-        {activeTab === TAB_NAMES.GRAPHICS && <div>Graphics</div>}
+        {activeTab === TAB_NAMES.GRAPHICS && <Graphics />}
       </div>
     </div>
   );
diff --git a/src/components/Map/Drawer/ExportDrawer/Graphics/Graphics.component.tsx b/src/components/Map/Drawer/ExportDrawer/Graphics/Graphics.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..547c2c14ed2b487a38bb5773552aa386ef84fadd
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Graphics/Graphics.component.tsx
@@ -0,0 +1,14 @@
+import { Export } from '../ExportCompound';
+
+export const Graphics = (): React.ReactNode => {
+  return (
+    <div data-testid="graphics-tab">
+      <Export>
+        <Export.Submap />
+        <Export.ImageSize />
+        <Export.ImageFormat />
+        <Export.DownloadGraphics />
+      </Export>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/ExportDrawer/Graphics/index.ts b/src/components/Map/Drawer/ExportDrawer/Graphics/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e82824ec6623b9e6e88f9c7b1374b449878e1fa4
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Graphics/index.ts
@@ -0,0 +1 @@
+export { Graphics } from './Graphics.component';
diff --git a/src/components/Map/Drawer/ExportDrawer/Network/Network.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/Network/Network.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..4bf77ac6c6bfd29c2bc9d3d2212198fedfee3f91
--- /dev/null
+++ b/src/components/Map/Drawer/ExportDrawer/Network/Network.component.test.tsx
@@ -0,0 +1,213 @@
+/* eslint-disable no-magic-numbers */
+import { compartmentPathwaysDetailsFixture } from '@/models/fixtures/compartmentPathways';
+import { configurationFixture } from '@/models/fixtures/configurationFixture';
+import { modelsFixture } from '@/models/fixtures/modelsFixture';
+import { statisticsFixture } from '@/models/fixtures/statisticsFixture';
+import { apiPath } from '@/redux/apiPath';
+import { CONFIGURATION_INITIAL_STORE_MOCK } from '@/redux/configuration/configuration.mock';
+import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
+import { AppDispatch, RootState } from '@/redux/store';
+import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { InitialStoreState } from '@/utils/testing/getReduxWrapperWithStore';
+import { render, screen } from '@testing-library/react';
+import { HttpStatusCode } from 'axios';
+import { act } from 'react-dom/test-utils';
+import { MockStoreEnhanced } from 'redux-mock-store';
+import { NETWORK_COLUMNS } from '../ExportCompound/ExportCompound.constant';
+import { Network } from './Network.component';
+
+const mockedAxiosClient = mockNetworkNewAPIResponse();
+
+const renderComponent = (
+  initialStore?: InitialStoreState,
+): { store: MockStoreEnhanced<Partial<RootState>, AppDispatch> } => {
+  const { Wrapper, store } = getReduxStoreWithActionsListener(initialStore);
+  return (
+    render(
+      <Wrapper>
+        <Network />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('Network - component', () => {
+  it('should render all network sections', () => {
+    renderComponent({
+      ...INITIAL_STORE_STATE_MOCK,
+      configuration: {
+        ...CONFIGURATION_INITIAL_STORE_MOCK,
+        main: {
+          ...CONFIGURATION_INITIAL_STORE_MOCK.main,
+          data: {
+            ...configurationFixture,
+            miriamTypes: {
+              compartment_label: {
+                commonName: 'Compartment',
+                homepage: '',
+                registryIdentifier: '',
+                uris: [''],
+              },
+            },
+          },
+        },
+      },
+      statistics: {
+        data: {
+          ...statisticsFixture,
+          reactionAnnotations: {
+            compartment_label: 1,
+            pathway: 0,
+          },
+        },
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+      compartmentPathways: {
+        data: compartmentPathwaysDetailsFixture,
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+    const annotations = screen.getByText('Select annotations');
+    const includedCompartmentPathways = screen.getByText('Select included compartment / pathways');
+    const excludedCompartmentPathways = screen.getByText('Select excluded compartment / pathways');
+    const downloadButton = screen.getByText('Download');
+
+    expect(annotations).toBeVisible();
+    expect(includedCompartmentPathways).toBeVisible();
+    expect(excludedCompartmentPathways).toBeVisible();
+    expect(downloadButton).toBeVisible();
+  });
+  it('should handle download button click and dispatch proper data', async () => {
+    mockedAxiosClient.onPost(apiPath.downloadNetworkCsv()).reply(HttpStatusCode.Ok, 'test');
+    const FIRST_COMPARMENT_PATHWAY_NAME = compartmentPathwaysDetailsFixture[0].name;
+    const FIRST_COMPARMENT_PATHWAY_ID = compartmentPathwaysDetailsFixture[0].id;
+    const SECOND_COMPARMENT_PATHWAY_NAME = compartmentPathwaysDetailsFixture[1].name;
+    const SECOND_COMPARMENT_PATHWAY_ID = compartmentPathwaysDetailsFixture[1].id;
+    const { store } = renderComponent({
+      ...INITIAL_STORE_STATE_MOCK,
+      configuration: {
+        ...CONFIGURATION_INITIAL_STORE_MOCK,
+        main: {
+          ...CONFIGURATION_INITIAL_STORE_MOCK.main,
+          data: {
+            ...configurationFixture,
+            miriamTypes: {
+              reaction: {
+                commonName: 'Reaction Label',
+                homepage: '',
+                registryIdentifier: '',
+                uris: [''],
+              },
+            },
+          },
+        },
+      },
+      statistics: {
+        data: {
+          ...statisticsFixture,
+          elementAnnotations: {
+            compartment: 1,
+            pathway: 0,
+          },
+          reactionAnnotations: {
+            reaction: 2,
+            path: 0,
+          },
+        },
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+      compartmentPathways: {
+        data: compartmentPathwaysDetailsFixture,
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+      models: {
+        data: modelsFixture,
+        loading: 'succeeded',
+        error: {
+          message: '',
+          name: '',
+        },
+      },
+    });
+
+    const annotations = screen.getByText('Select annotations');
+
+    await act(() => {
+      annotations.click();
+    });
+    const annotationInput = screen.getByLabelText('Reaction Label');
+
+    await act(() => {
+      annotationInput.click();
+    });
+
+    expect(annotationInput).toBeChecked();
+
+    const includedCompartmentPathways = screen.getByText('Select included compartment / pathways');
+
+    await act(() => {
+      includedCompartmentPathways.click();
+    });
+    const includedCompartmentPathwaysInput = screen.getAllByLabelText(
+      FIRST_COMPARMENT_PATHWAY_NAME,
+    )[0];
+
+    await act(() => {
+      includedCompartmentPathwaysInput.click();
+    });
+
+    expect(includedCompartmentPathwaysInput).toBeChecked();
+
+    const excludedCompartmentPathways = screen.getByText('Select excluded compartment / pathways');
+
+    await act(() => {
+      excludedCompartmentPathways.click();
+    });
+    const excludedCompartmentPathwaysInput = screen.getAllByLabelText(
+      SECOND_COMPARMENT_PATHWAY_NAME,
+    )[1];
+
+    await act(() => {
+      excludedCompartmentPathwaysInput.click();
+    });
+
+    expect(excludedCompartmentPathwaysInput).toBeChecked();
+
+    const downloadButton = screen.getByText('Download');
+
+    await act(() => {
+      downloadButton.click();
+    });
+
+    const actions = store.getActions();
+
+    const firstAction = actions[0];
+    expect(firstAction.meta.arg).toEqual({
+      columns: NETWORK_COLUMNS,
+      submaps: modelsFixture.map(item => item.idObject),
+      annotations: ['reaction'],
+      includedCompartmentIds: [FIRST_COMPARMENT_PATHWAY_ID],
+      excludedCompartmentIds: [SECOND_COMPARMENT_PATHWAY_ID],
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/ExportDrawer/Network/Network.component.tsx b/src/components/Map/Drawer/ExportDrawer/Network/Network.component.tsx
index 1438a0851f3581298f226532ff874bf44821a1b6..48f87045de1809a1062674b9adcb52d447717d33 100644
--- a/src/components/Map/Drawer/ExportDrawer/Network/Network.component.tsx
+++ b/src/components/Map/Drawer/ExportDrawer/Network/Network.component.tsx
@@ -1,15 +1,14 @@
 import { Export } from '../ExportCompound';
+import { ANNOTATIONS_TYPE } from '../ExportCompound/ExportCompound.constant';
 
 export const Network = (): React.ReactNode => {
   return (
     <div data-testid="export-tab">
       <Export>
-        <Export.Types />
-        <Export.Columns />
-        <Export.Annotations />
+        <Export.Annotations type={ANNOTATIONS_TYPE.NETWORK} />
         <Export.IncludedCompartmentPathways />
         <Export.ExcludedCompartmentPathways />
-        <Export.DownloadElements />
+        <Export.DownloadNetwork />
       </Export>
     </div>
   );
diff --git a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.test.tsx b/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.test.tsx
index 37ede68975b5ade8a9631fc4d13d80d1ecfd4d2c..081a86ba29e4f8f4651e67b9dcb412380a21f5d4 100644
--- a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.test.tsx
+++ b/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.test.tsx
@@ -17,6 +17,7 @@ import { apiPath } from '@/redux/apiPath';
 import { CORE_PD_MODEL_MOCK } from '@/models/mocks/modelsMock';
 import { MODELS_INITIAL_STATE_MOCK } from '@/redux/models/models.mock';
 import { parseOverlayBioEntityToOlRenderingFormat } from '@/redux/overlayBioEntity/overlayBioEntity.utils';
+import { BASE_API_URL } from '@/constants';
 import { OverlayListItem } from './OverlayListItem.component';
 
 const mockedAxiosNewClient = mockNetworkNewAPIResponse();
@@ -111,6 +112,29 @@ describe('OverlayListItem - component', () => {
     });
   });
 
-  // TODO implement when connecting logic to component
-  it.skip('should trigger download overlay to PC on download button click', () => {});
+  it('should trigger download overlay to PC on download button click', () => {
+    const OVERLAY_ID = 21;
+    renderComponent({
+      map: {
+        ...initialMapStateFixture,
+        data: { ...initialMapStateFixture.data, backgroundId: EMPTY_BACKGROUND_ID },
+      },
+      backgrounds: { ...BACKGROUND_INITIAL_STATE_MOCK, data: BACKGROUNDS_MOCK },
+      overlayBioEntity: { ...OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK, overlaysId: [OVERLAY_ID] },
+      models: { ...MODELS_INITIAL_STATE_MOCK, data: [CORE_PD_MODEL_MOCK] },
+    });
+
+    const downloadButton = screen.getByText('Download');
+
+    expect(downloadButton).toBeVisible();
+
+    const windowOpenMock = jest.spyOn(window, 'open').mockImplementation();
+
+    downloadButton.click();
+
+    expect(windowOpenMock).toHaveBeenCalledWith(
+      `${BASE_API_URL}/${apiPath.downloadOverlay(OVERLAY_ID)}`,
+      '_blank',
+    );
+  });
 });
diff --git a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.tsx
index 21eefae1d72c6821d494efd7ed29c8b34553bee9..82c5965d44326e1440e1752719094222db49f3b9 100644
--- a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.tsx
+++ b/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.tsx
@@ -1,7 +1,7 @@
 import { Button } from '@/shared/Button';
 import Image from 'next/image';
 import spinnerIcon from '@/assets/vectors/icons/spinner.svg';
-import { useOverlay } from './hooks/useOverlay';
+import { useOverlay } from '../../hooks/useOverlay';
 
 interface OverlayListItemProps {
   name: string;
@@ -9,8 +9,8 @@ interface OverlayListItemProps {
 }
 
 export const OverlayListItem = ({ name, overlayId }: OverlayListItemProps): JSX.Element => {
-  const onDownloadOverlay = (): void => {};
-  const { toggleOverlay, isOverlayActive, isOverlayLoading } = useOverlay(overlayId);
+  const { toggleOverlay, isOverlayActive, isOverlayLoading, downloadOverlay } =
+    useOverlay(overlayId);
 
   return (
     <li className="flex flex-row flex-nowrap justify-between pl-5 [&:not(:last-of-type)]:mb-4">
@@ -32,7 +32,7 @@ export const OverlayListItem = ({ name, overlayId }: OverlayListItemProps): JSX.
           )}
           {isOverlayActive || isOverlayActive ? 'Disable' : 'View'}
         </Button>
-        <Button className="max-h-8" variantStyles="ghost" onClick={onDownloadOverlay}>
+        <Button className="max-h-8" variantStyles="ghost" onClick={downloadOverlay}>
           Download
         </Button>
       </div>
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx
index b7c754c8f76d782d67e55a0beec1f0c2f1a3021c..9fb75c283445be61f5ea351185806fb7ca790eb1 100644
--- a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx
@@ -7,7 +7,6 @@ import {
   getReduxWrapperWithStore,
 } from '@/utils/testing/getReduxWrapperWithStore';
 import { AppDispatch, RootState, StoreType } from '@/redux/store';
-import { DEFAULT_ERROR } from '@/constants/errors';
 import { drawerOverlaysStepOneFixture } from '@/redux/drawer/drawerFixture';
 import { MockStoreEnhanced } from 'redux-mock-store';
 import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
@@ -19,6 +18,7 @@ import {
   createdOverlayFixture,
   uploadedOverlayFileContentFixture,
 } from '@/models/fixtures/overlaysFixture';
+import { OVERLAYS_INITIAL_STATE_MOCK } from '@/redux/overlays/overlays.mock';
 import { UserOverlayForm } from './UserOverlayForm.component';
 
 const mockedAxiosClient = mockNetworkResponse();
@@ -81,15 +81,7 @@ describe('UserOverlayForm - Component', () => {
         loading: 'succeeded',
         error: { message: '', name: '' },
       },
-      overlays: {
-        data: [],
-        loading: 'idle',
-        error: DEFAULT_ERROR,
-        addOverlay: {
-          loading: 'idle',
-          error: DEFAULT_ERROR,
-        },
-      },
+      overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
 
     fireEvent.change(screen.getByTestId('overlay-name'), { target: { value: 'Test Overlay' } });
@@ -112,15 +104,7 @@ describe('UserOverlayForm - Component', () => {
         loading: 'succeeded',
         error: { message: '', name: '' },
       },
-      overlays: {
-        data: [],
-        loading: 'idle',
-        error: DEFAULT_ERROR,
-        addOverlay: {
-          loading: 'idle',
-          error: DEFAULT_ERROR,
-        },
-      },
+      overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
 
     fireEvent.change(screen.getByTestId('overlay-name'), { target: { value: 'Test Overlay' } });
@@ -139,15 +123,7 @@ describe('UserOverlayForm - Component', () => {
 
   it('should update the form inputs based on overlay content provided by elements list', async () => {
     renderComponent({
-      overlays: {
-        data: [],
-        loading: 'idle',
-        error: DEFAULT_ERROR,
-        addOverlay: {
-          loading: 'idle',
-          error: DEFAULT_ERROR,
-        },
-      },
+      overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
 
     fireEvent.change(screen.getByTestId('overlay-name'), { target: { value: 'Test Overlay' } });
@@ -171,15 +147,7 @@ describe('UserOverlayForm - Component', () => {
       type: 'text/plain',
     });
     renderComponent({
-      overlays: {
-        data: [],
-        loading: 'idle',
-        error: DEFAULT_ERROR,
-        addOverlay: {
-          loading: 'idle',
-          error: DEFAULT_ERROR,
-        },
-      },
+      overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
 
     fireEvent.change(screen.getByTestId('dropzone-input'), {
@@ -192,15 +160,7 @@ describe('UserOverlayForm - Component', () => {
 
   it('should not submit when form is not filled', async () => {
     renderComponent({
-      overlays: {
-        data: [],
-        loading: 'idle',
-        error: DEFAULT_ERROR,
-        addOverlay: {
-          loading: 'idle',
-          error: DEFAULT_ERROR,
-        },
-      },
+      overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
     expect(screen.getByTestId('overlay-description')).toHaveValue('');
     fireEvent.click(screen.getByLabelText('upload overlay'));
@@ -214,15 +174,7 @@ describe('UserOverlayForm - Component', () => {
         loading: 'succeeded',
         error: { message: '', name: '' },
       },
-      overlays: {
-        data: [],
-        loading: 'idle',
-        error: DEFAULT_ERROR,
-        addOverlay: {
-          loading: 'idle',
-          error: DEFAULT_ERROR,
-        },
-      },
+      overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
 
     const backButton = screen.getByRole('back-button');
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.test.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.test.tsx
index e5e7267c317de2608eead6063a5149f397b2dcad..116c9a792f8b7534412468a0631d4cc410ca30a9 100644
--- a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.test.tsx
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.test.tsx
@@ -61,6 +61,7 @@ describe('UserOverlays component', () => {
         modalTitle: '',
         overviewImagesState: {},
         molArtState: {},
+        editOverlayState: null,
       },
     });
     screen.getByLabelText('login button').click();
@@ -81,4 +82,16 @@ describe('UserOverlays component', () => {
 
     expect(screen.getByLabelText('add overlay button')).toBeInTheDocument();
   });
+  it('renders user overlays section when user is authenticated', () => {
+    renderComponent({
+      user: {
+        loading: 'succeeded',
+        authenticated: true,
+        error: { name: '', message: '' },
+        login: 'test',
+      },
+    });
+
+    expect(screen.getByText('Without group')).toBeInTheDocument();
+  });
 });
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.tsx
index 2db18b4201bb8ce15a36ea59994a5238e011cb79..08e161b2cb9ee434c28220c41f7636e56b8fa1e6 100644
--- a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.tsx
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlays.component.tsx
@@ -4,6 +4,7 @@ import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import { openLoginModal } from '@/redux/modal/modal.slice';
 import { authenticatedUserSelector, loadingUserSelector } from '@/redux/user/user.selectors';
 import { Button } from '@/shared/Button';
+import { UserOverlaysWithoutGroup } from './UserOverlaysWithoutGroup';
 
 export const UserOverlays = (): JSX.Element => {
   const dispatch = useAppDispatch();
@@ -20,11 +21,11 @@ export const UserOverlays = (): JSX.Element => {
   };
 
   return (
-    <div className="p-6">
+    <div className="py-6">
       {isPending && <h1>Loading</h1>}
 
       {!isPending && !authenticatedUser && (
-        <>
+        <div className="px-6">
           <p className="mb-5 font-semibold">User provided overlays:</p>
           <p className="mb-5 text-sm">
             You are not logged in, please login to upload and view custom overlays
@@ -32,16 +33,19 @@ export const UserOverlays = (): JSX.Element => {
           <Button onClick={handleLoginClick} aria-label="login button">
             Login
           </Button>
-        </>
+        </div>
       )}
 
       {authenticatedUser && (
-        <div className="flex items-center justify-between">
-          <p>User provided overlays:</p>
-          <Button onClick={handleAddOverlay} aria-label="add overlay button">
-            Add overlay
-          </Button>
-        </div>
+        <>
+          <div className="flex items-center justify-between px-6">
+            <p className="font-semibold">User provided overlays:</p>
+            <Button onClick={handleAddOverlay} aria-label="add overlay button">
+              Add overlay
+            </Button>
+          </div>
+          <UserOverlaysWithoutGroup />
+        </>
       )}
     </div>
   );
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/UserOverlayActions.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/UserOverlayActions.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..16b0cda2c027907d6da026dcddc5d0db25d52a1a
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/UserOverlayActions.component.tsx
@@ -0,0 +1,54 @@
+import { useSelect } from 'downshift';
+import { twMerge } from 'tailwind-merge';
+import React, { useMemo } from 'react';
+import { MapOverlay } from '@/types/models';
+import { Icon } from '@/shared/Icon';
+import { useUserOverlayActions } from './hooks/useUserOverlayActions';
+import { ACTION_TYPES } from './UserOverlayActions.constants';
+
+type UserOverlayActionsProps = {
+  overlay: MapOverlay;
+};
+
+export const UserOverlayActions = ({ overlay }: UserOverlayActionsProps): React.ReactNode => {
+  const actions = useMemo(() => Object.values(ACTION_TYPES), []);
+  const { isOpen, getToggleButtonProps, getMenuProps, getItemProps } = useSelect({
+    items: actions,
+  });
+
+  const { handleActionClick } = useUserOverlayActions(overlay);
+
+  return (
+    <div className="relative">
+      <div
+        className="flex cursor-pointer justify-between bg-white p-2"
+        {...getToggleButtonProps()}
+        data-testid="actions-button"
+      >
+        <Icon name="three-dots" className="h-[22px] w-[4px]" />
+      </div>
+      <ul
+        className={twMerge(
+          `absolute right-0 top-0 z-10 w-28 rounded-lg border border-[#DBD9D9] bg-white px-2.5 text-center shadow-md`,
+          !isOpen && 'hidden',
+        )}
+        {...getMenuProps()}
+      >
+        {isOpen &&
+          actions.map((item, index) => (
+            <li
+              key={item}
+              {...getItemProps({
+                item,
+                index,
+                onClick: () => handleActionClick(item),
+              })}
+              className='relative cursor-pointer px-2.5 py-4 text-xs before:absolute before:bottom-0 before:left-1/2 before:top-full before:block before:h-px before:w-11/12 before:-translate-x-1/2 before:bg-[#E3E3E3] before:content-[""] before:last-of-type:hidden'
+            >
+              {item}
+            </li>
+          ))}
+      </ul>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/UserOverlayActions.constants.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/UserOverlayActions.constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cf82dee881829f9b3f50100681c434d8b565ab95
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/UserOverlayActions.constants.ts
@@ -0,0 +1,4 @@
+export const ACTION_TYPES = {
+  EDIT: 'Edit',
+  DOWNLOAD: 'Download',
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/hooks/useUserOverlayActions.test.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/hooks/useUserOverlayActions.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b7e7135bb456ff9d20bd35780c9c673bbec2a257
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/hooks/useUserOverlayActions.test.ts
@@ -0,0 +1,68 @@
+/* eslint-disable no-magic-numbers */
+import { overlayFixture } from '@/models/fixtures/overlaysFixture';
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { renderHook } from '@testing-library/react';
+import { act } from 'react-dom/test-utils';
+import { BASE_API_URL } from '@/constants';
+import { apiPath } from '@/redux/apiPath';
+import { useUserOverlayActions } from './useUserOverlayActions';
+
+describe('useUserOverlayActions', () => {
+  it('should handle handleActionClick based on edit action', async () => {
+    const { Wrapper, store } = getReduxStoreWithActionsListener({});
+
+    const {
+      result: {
+        current: { handleActionClick },
+      },
+    } = renderHook(() => useUserOverlayActions(overlayFixture), {
+      wrapper: Wrapper,
+    });
+
+    await act(() => {
+      handleActionClick('Edit');
+    });
+
+    const actions = store.getActions();
+
+    const FIRST_ACTION = actions[0];
+
+    expect(FIRST_ACTION.payload).toBe(overlayFixture);
+    expect(FIRST_ACTION.type).toBe('modal/openEditOverlayModal');
+  });
+  it('should handle handleActionClick based on download action', async () => {
+    const { Wrapper } = getReduxStoreWithActionsListener({});
+
+    const {
+      result: {
+        current: { handleActionClick },
+      },
+    } = renderHook(() => useUserOverlayActions(overlayFixture), {
+      wrapper: Wrapper,
+    });
+
+    const windowOpenMock = jest.spyOn(window, 'open').mockImplementation();
+
+    await act(() => {
+      handleActionClick('Download');
+    });
+
+    expect(windowOpenMock).toHaveBeenCalledWith(
+      `${BASE_API_URL}/${apiPath.downloadOverlay(overlayFixture.idObject)}`,
+      '_blank',
+    );
+  });
+  it('should throw Error if handleActionClick action is not valid', async () => {
+    const { Wrapper } = getReduxStoreWithActionsListener({});
+
+    const {
+      result: {
+        current: { handleActionClick },
+      },
+    } = renderHook(() => useUserOverlayActions(overlayFixture), {
+      wrapper: Wrapper,
+    });
+
+    expect(() => handleActionClick('Wrong Action')).toThrow('Wrong Action is not valid');
+  });
+});
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/hooks/useUserOverlayActions.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/hooks/useUserOverlayActions.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1b10cb09b23152180c8789be7a4dbf37e1ae7a4b
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/hooks/useUserOverlayActions.ts
@@ -0,0 +1,39 @@
+import { BASE_API_URL } from '@/constants';
+import { apiPath } from '@/redux/apiPath';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { openEditOverlayModal } from '@/redux/modal/modal.slice';
+import { MapOverlay } from '@/types/models';
+import { ACTION_TYPES } from '../UserOverlayActions.constants';
+
+type UseUserOverlayActionsReturn = {
+  handleActionClick: (action: string) => void;
+};
+
+export const useUserOverlayActions = (overlay: MapOverlay): UseUserOverlayActionsReturn => {
+  const dispatch = useAppDispatch();
+
+  const handleDownloadOverlay = (): void => {
+    window.open(`${BASE_API_URL}/${apiPath.downloadOverlay(overlay.idObject)}`, '_blank');
+  };
+
+  const handleEditOverlay = (): void => {
+    dispatch(openEditOverlayModal(overlay));
+  };
+
+  const handleActionClick = (action: string): void => {
+    switch (action) {
+      case ACTION_TYPES.DOWNLOAD:
+        handleDownloadOverlay();
+        break;
+      case ACTION_TYPES.EDIT:
+        handleEditOverlay();
+        break;
+      default:
+        throw new Error(`${action} is not valid`);
+    }
+  };
+
+  return {
+    handleActionClick,
+  };
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/index.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1ebaabbff8fbc3d71d4f6a9142dcf2ddf3eb8f46
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayActions/index.ts
@@ -0,0 +1 @@
+export { UserOverlayActions } from './UserOverlayActions.component';
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayInfo/UserOverlayInfo.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayInfo/UserOverlayInfo.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..78dff20cd2f87dc290da3ff75d77af02dfa316c6
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayInfo/UserOverlayInfo.component.tsx
@@ -0,0 +1,32 @@
+/* eslint-disable no-magic-numbers */
+import { twMerge } from 'tailwind-merge';
+import React, { useMemo } from 'react';
+import { Icon } from '@/shared/Icon';
+
+type UserOverlayInfoProps = {
+  description: string;
+  name: string;
+};
+
+export const UserOverlayInfo = ({ description, name }: UserOverlayInfoProps): React.ReactNode => {
+  const isOverflowPossibility = useMemo(() => name.length > 25, [name]);
+
+  return (
+    <div className="flex items-center gap-x-2.5">
+      <span className="text-sm">{name}</span>
+
+      <div className="group relative" data-testid="info">
+        <Icon name="info" className="h-4 w-4 fill-black" />
+
+        <div
+          className={twMerge(
+            'absolute bottom-0 left-0 top-auto z-20 hidden min-w-[200px] max-w-xs rounded-lg bg-white px-3  py-4 drop-shadow-md group-hover:block',
+            isOverflowPossibility && 'min-w-[100px] max-w-[200px]',
+          )}
+        >
+          <p className="text-xs">{description}</p>
+        </div>
+      </div>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayListItem.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayListItem.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..e96e8751115186f741bafd321277d9a0fb993965
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/UserOverlayListItem.component.tsx
@@ -0,0 +1,62 @@
+import { Button } from '@/shared/Button';
+import { MapOverlay } from '@/types/models';
+import { twMerge } from 'tailwind-merge';
+import Image from 'next/image';
+import spinnerIcon from '@/assets/vectors/icons/spinner.svg';
+import { useOverlay } from '../../../hooks/useOverlay';
+import { UserOverlayActions } from './UserOverlayActions';
+import { UserOverlayInfo } from './UserOverlayInfo/UserOverlayInfo.component';
+import { useDragAndDrop } from './hooks/useDragAndDrop';
+
+type OverlayListItemProps = {
+  index: number;
+  moveUserOverlay: (dragIndex: number, hoverIndex: number) => void;
+  userOverlay: MapOverlay;
+  updateUserOverlaysOrder: () => void;
+};
+
+export const UserOverlayListItem = ({
+  index,
+  moveUserOverlay,
+  userOverlay,
+  updateUserOverlaysOrder,
+}: OverlayListItemProps): JSX.Element => {
+  const { toggleOverlay, isOverlayActive, isOverlayLoading } = useOverlay(userOverlay.idObject);
+  const { dragRef, dropRef, isDragging } = useDragAndDrop({
+    onDrop: updateUserOverlaysOrder,
+    onHover: moveUserOverlay,
+    index,
+  });
+
+  return (
+    <li
+      ref={node => dragRef(dropRef(node))}
+      className={twMerge(
+        'flex flex-row flex-nowrap items-center justify-between overflow-visible py-4 pl-10 pr-5',
+        isDragging ? 'opacity-0' : 'opacity-100',
+      )}
+    >
+      <UserOverlayInfo description={userOverlay.description} name={userOverlay.name} />
+      <div className="flex flex-row flex-nowrap items-center">
+        <Button
+          variantStyles="ghost"
+          className="mr-4 max-h-8 flex-none gap-1.5"
+          onClick={toggleOverlay}
+          data-testid="toggle-overlay-button"
+        >
+          {isOverlayLoading && (
+            <Image
+              src={spinnerIcon}
+              alt="spinner icon"
+              height={12}
+              width={12}
+              className="animate-spin"
+            />
+          )}
+          {isOverlayActive || isOverlayLoading ? 'Disable' : 'View'}
+        </Button>
+        <UserOverlayActions overlay={userOverlay} />
+      </div>
+    </li>
+  );
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/hooks/useDragAndDrop.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/hooks/useDragAndDrop.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6e3eebc9b1cd5ed60ab25411efb8e581a5161135
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/hooks/useDragAndDrop.ts
@@ -0,0 +1,51 @@
+/* eslint-disable no-param-reassign */
+import { ConnectDragSource, ConnectDropTarget, useDrag, useDrop } from 'react-dnd';
+
+const ITEM_TYPE = 'card';
+
+type UseDragAndDropProps = {
+  index: number;
+  onHover: (dragIndex: number, hoverIndex: number) => void;
+  onDrop: () => void;
+};
+
+type UseDragAndDropReturn = {
+  isDragging: boolean;
+  dragRef: ConnectDragSource;
+  dropRef: ConnectDropTarget;
+};
+
+export const useDragAndDrop = ({
+  index,
+  onDrop,
+  onHover,
+}: UseDragAndDropProps): UseDragAndDropReturn => {
+  const [{ isDragging }, dragRef] = useDrag({
+    type: ITEM_TYPE,
+    item: { index },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  });
+
+  const [, dropRef] = useDrop({
+    accept: ITEM_TYPE,
+    hover: (item: { index: number }) => {
+      const dragIndex = item.index;
+      const hoverIndex = index;
+
+      onHover(dragIndex, hoverIndex);
+
+      item.index = hoverIndex;
+    },
+    drop() {
+      onDrop();
+    },
+  });
+
+  return {
+    isDragging,
+    dragRef,
+    dropRef,
+  };
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/index.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1950f98f4a85ba30819bc6a4a09ee28a4e2e8e43
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlayListItem/index.ts
@@ -0,0 +1 @@
+export { UserOverlayListItem } from './UserOverlayListItem.component';
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.component.test.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..1174b330a03faa1d38a7ae3b3fb93b4682bc0b3f
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.component.test.tsx
@@ -0,0 +1,345 @@
+/* eslint-disable no-magic-numbers */
+import { render, screen } from '@testing-library/react';
+import { StoreType } from '@/redux/store';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { overlayFixture, overlaysFixture } from '@/models/fixtures/overlaysFixture';
+import { apiPath } from '@/redux/apiPath';
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { act } from 'react-dom/test-utils';
+import { BASE_API_URL } from '@/constants';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { HttpStatusCode } from 'axios';
+import { OVERLAYS_INITIAL_STATE_MOCK } from '@/redux/overlays/overlays.mock';
+import { MODAL_INITIAL_STATE_MOCK } from '@/redux/modal/modal.mock';
+import { UserOverlaysWithoutGroup } from './UserOverlaysWithoutGroup.component';
+
+const mockedAxiosClient = mockNetworkResponse();
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <UserOverlaysWithoutGroup />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('UserOverlaysWithoutGroup - component', () => {
+  it('should render list of overlays', async () => {
+    mockedAxiosClient
+      .onGet(apiPath.getAllUserOverlaysByCreatorQuery({ creator: 'test', publicOverlay: false }))
+      .reply(HttpStatusCode.Ok, overlaysFixture);
+    renderComponent({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: {
+        ...OVERLAYS_INITIAL_STATE_MOCK,
+        userOverlays: {
+          data: overlaysFixture,
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    const withoutGroupTitle = screen.getByText('Without group');
+
+    expect(withoutGroupTitle).toBeVisible();
+
+    await act(() => {
+      withoutGroupTitle.click();
+    });
+
+    for (let index = 0; index < overlaysFixture.length; index += 1) {
+      const overlay = overlaysFixture[index];
+      expect(screen.getByText(overlay.name)).toBeVisible();
+    }
+  });
+
+  it('should display loading message if fetching user overlays is pending', async () => {
+    mockedAxiosClient
+      .onGet(apiPath.getAllUserOverlaysByCreatorQuery({ creator: 'test', publicOverlay: false }))
+      .reply(HttpStatusCode.Ok, overlaysFixture);
+
+    renderComponent({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: OVERLAYS_INITIAL_STATE_MOCK,
+    });
+
+    expect(screen.getByText('Loading...')).toBeInTheDocument();
+  });
+
+  it('should display functioning action types list after click', async () => {
+    renderComponent({
+      modal: MODAL_INITIAL_STATE_MOCK,
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: {
+        ...OVERLAYS_INITIAL_STATE_MOCK,
+        userOverlays: {
+          data: overlaysFixture,
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    const withoutGroupTitle = screen.getByText('Without group');
+
+    expect(withoutGroupTitle).toBeVisible();
+
+    await act(() => {
+      withoutGroupTitle.click();
+    });
+
+    const actionsButton = screen.getAllByTestId('actions-button');
+
+    const firstActionsButton = actionsButton[0];
+
+    expect(firstActionsButton).toBeVisible();
+
+    await act(() => {
+      firstActionsButton.click();
+    });
+
+    expect(screen.getByText('Download')).toBeVisible();
+    expect(screen.getByText('Edit')).toBeVisible();
+  });
+  it('should display overlay description on info icon hover/click', async () => {
+    mockedAxiosClient
+      .onGet(apiPath.getAllUserOverlaysByCreatorQuery({ creator: 'test', publicOverlay: false }))
+      .reply(HttpStatusCode.Ok, [overlayFixture]);
+    renderComponent({
+      modal: MODAL_INITIAL_STATE_MOCK,
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: {
+        ...OVERLAYS_INITIAL_STATE_MOCK,
+        userOverlays: {
+          data: [overlayFixture],
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    const withoutGroupTitle = screen.getByText('Without group');
+
+    expect(withoutGroupTitle).toBeVisible();
+
+    await act(() => {
+      withoutGroupTitle.click();
+    });
+
+    const info = screen.getByTestId('info');
+
+    expect(info).toBeVisible();
+
+    await act(() => {
+      info.click();
+    });
+
+    expect(screen.getByText(overlayFixture.description)).toBeVisible();
+  });
+  it('should change state to display edit overlay modal after edit action click', async () => {
+    const { store } = renderComponent({
+      modal: MODAL_INITIAL_STATE_MOCK,
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: {
+        ...OVERLAYS_INITIAL_STATE_MOCK,
+        userOverlays: {
+          data: overlaysFixture,
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    const withoutGroupTitle = screen.getByText('Without group');
+
+    expect(withoutGroupTitle).toBeVisible();
+
+    await act(() => {
+      withoutGroupTitle.click();
+    });
+
+    const actionsButton = screen.getAllByTestId('actions-button');
+
+    const firstActionsButton = actionsButton[0];
+
+    expect(firstActionsButton).toBeVisible();
+
+    await act(() => {
+      firstActionsButton.click();
+    });
+
+    const editAction = screen.getByText('Edit');
+
+    expect(editAction).toBeVisible();
+
+    await act(() => {
+      editAction.click();
+    });
+
+    const { modalName, isOpen } = store.getState().modal;
+
+    expect(modalName).toBe('edit-overlay');
+    expect(isOpen).toBe(true);
+  });
+  it('should display propert text for toggle overlay button', async () => {
+    renderComponent({
+      modal: MODAL_INITIAL_STATE_MOCK,
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: {
+        ...OVERLAYS_INITIAL_STATE_MOCK,
+        userOverlays: {
+          data: [overlayFixture],
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+      overlayBioEntity: {
+        data: [],
+        overlaysId: [],
+      },
+    });
+
+    const withoutGroupTitle = screen.getByText('Without group');
+
+    expect(withoutGroupTitle).toBeVisible();
+
+    await act(() => {
+      withoutGroupTitle.click();
+    });
+
+    const toggleOverlayButton = screen.getByTestId('toggle-overlay-button');
+
+    expect(toggleOverlayButton).toBeVisible();
+
+    await act(() => {
+      toggleOverlayButton.click();
+    });
+
+    expect(screen.getByTestId('toggle-overlay-button')).toHaveTextContent('Disable');
+  });
+  it('should call window.open with download link after download action click', async () => {
+    renderComponent({
+      modal: MODAL_INITIAL_STATE_MOCK,
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: {
+        ...OVERLAYS_INITIAL_STATE_MOCK,
+        userOverlays: {
+          data: [overlayFixture],
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    const withoutGroupTitle = screen.getByText('Without group');
+
+    expect(withoutGroupTitle).toBeVisible();
+
+    await act(() => {
+      withoutGroupTitle.click();
+    });
+
+    const actionButton = screen.getByTestId('actions-button');
+
+    await act(() => {
+      actionButton.click();
+    });
+
+    const windowOpenMock = jest.spyOn(window, 'open').mockImplementation();
+
+    const downloadButton = screen.getByText('Download');
+    expect(downloadButton).toBeVisible();
+
+    await act(() => {
+      downloadButton.click();
+    });
+
+    expect(windowOpenMock).toHaveBeenCalledWith(
+      `${BASE_API_URL}/${apiPath.downloadOverlay(overlayFixture.idObject)}`,
+      '_blank',
+    );
+  });
+  it('should display spinner icon if user overlay is loading', async () => {
+    const OVERLAY_ID = overlayFixture.idObject;
+    renderComponent({
+      modal: MODAL_INITIAL_STATE_MOCK,
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: {
+        ...OVERLAYS_INITIAL_STATE_MOCK,
+        userOverlays: {
+          data: [overlayFixture],
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+      overlayBioEntity: {
+        data: {
+          [OVERLAY_ID]: {},
+        },
+        overlaysId: [OVERLAY_ID],
+      },
+    });
+
+    const withoutGroupTitle = screen.getByText('Without group');
+
+    expect(withoutGroupTitle).toBeVisible();
+
+    await act(() => {
+      withoutGroupTitle.click();
+    });
+
+    expect(screen.getByAltText('spinner icon')).toBeVisible();
+    expect(screen.getByText('Disable')).toBeVisible();
+  });
+});
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..ad61cc51b83e80675de64cddaf2e163b9d9b48c1
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.component.tsx
@@ -0,0 +1,49 @@
+import {
+  Accordion,
+  AccordionItem,
+  AccordionItemButton,
+  AccordionItemHeading,
+  AccordionItemPanel,
+} from '@/shared/Accordion';
+import { DndProvider } from 'react-dnd';
+import { HTML5Backend } from 'react-dnd-html5-backend';
+import { UserOverlayListItem } from './UserOverlayListItem';
+import { useUserOverlays } from './hooks/useUserOverlays';
+
+export const UserOverlaysWithoutGroup = (): React.ReactNode => {
+  const { moveUserOverlayListItem, updateUserOverlaysOrder, isPending, userOverlaysList } =
+    useUserOverlays();
+
+  return (
+    <DndProvider backend={HTML5Backend}>
+      <div className="mt-2.5">
+        <Accordion allowZeroExpanded>
+          <AccordionItem className="border-b-0">
+            <AccordionItemHeading>
+              <AccordionItemButton className="px-6 text-sm font-semibold">
+                Without group
+              </AccordionItemButton>
+            </AccordionItemHeading>
+            <AccordionItemPanel>
+              {isPending ? (
+                <span className="py-4 pl-10 pr-5">Loading...</span>
+              ) : (
+                <ul>
+                  {userOverlaysList?.map((userOverlay, index) => (
+                    <UserOverlayListItem
+                      moveUserOverlay={moveUserOverlayListItem}
+                      key={userOverlay.idObject}
+                      index={index}
+                      userOverlay={userOverlay}
+                      updateUserOverlaysOrder={updateUserOverlaysOrder}
+                    />
+                  ))}
+                </ul>
+              )}
+            </AccordionItemPanel>
+          </AccordionItem>
+        </Accordion>
+      </div>
+    </DndProvider>
+  );
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.utils.test.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.utils.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8c07bab617c8bcb8d8d65ce44031e06f8f6fab6e
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.utils.test.ts
@@ -0,0 +1,230 @@
+/* eslint-disable no-magic-numbers */
+import { MapOverlay } from '@/types/models';
+import { moveArrayElement } from './UserOverlaysWithoutGroup.utils';
+
+const INPUT_ARRAY: MapOverlay[] = [
+  {
+    name: 'Overlay1',
+    description: 'Description1',
+    type: 'Type1',
+    googleLicenseConsent: true,
+    creator: 'Creator1',
+    genomeType: 'GenomeType1',
+    genomeVersion: 'GenomeVersion1',
+    idObject: 1,
+    publicOverlay: false,
+    order: 1,
+  },
+  {
+    name: 'Overlay2',
+    description: 'Description2',
+    type: 'Type2',
+    googleLicenseConsent: false,
+    creator: 'Creator2',
+    genomeType: 'GenomeType2',
+    genomeVersion: 'GenomeVersion2',
+    idObject: 2,
+    publicOverlay: true,
+    order: 2,
+  },
+  {
+    name: 'Overlay3',
+    description: 'Description3',
+    type: 'Type3',
+    googleLicenseConsent: true,
+    creator: 'Creator3',
+    genomeType: 'GenomeType3',
+    genomeVersion: 'GenomeVersion3',
+    idObject: 3,
+    publicOverlay: false,
+    order: 3,
+  },
+];
+
+describe('moveArrayElement', () => {
+  it('should move an element down in the array', () => {
+    const expectedResult: MapOverlay[] = [
+      {
+        name: 'Overlay1',
+        description: 'Description1',
+        type: 'Type1',
+        googleLicenseConsent: true,
+        creator: 'Creator1',
+        genomeType: 'GenomeType1',
+        genomeVersion: 'GenomeVersion1',
+        idObject: 1,
+        publicOverlay: false,
+        order: 1,
+      },
+      {
+        name: 'Overlay3',
+        description: 'Description3',
+        type: 'Type3',
+        googleLicenseConsent: true,
+        creator: 'Creator3',
+        genomeType: 'GenomeType3',
+        genomeVersion: 'GenomeVersion3',
+        idObject: 3,
+        publicOverlay: false,
+        order: 3,
+      },
+      {
+        name: 'Overlay2',
+        description: 'Description2',
+        type: 'Type2',
+        googleLicenseConsent: false,
+        creator: 'Creator2',
+        genomeType: 'GenomeType2',
+        genomeVersion: 'GenomeVersion2',
+        idObject: 2,
+        publicOverlay: true,
+        order: 2,
+      },
+    ];
+
+    const result = moveArrayElement(INPUT_ARRAY, 1, 2);
+
+    expect(result).toEqual(expectedResult);
+  });
+
+  it('should move an element up in the array', () => {
+    const expectedResult: MapOverlay[] = [
+      {
+        name: 'Overlay1',
+        description: 'Description1',
+        type: 'Type1',
+        googleLicenseConsent: true,
+        creator: 'Creator1',
+        genomeType: 'GenomeType1',
+        genomeVersion: 'GenomeVersion1',
+        idObject: 1,
+        publicOverlay: false,
+        order: 1,
+      },
+      {
+        name: 'Overlay3',
+        description: 'Description3',
+        type: 'Type3',
+        googleLicenseConsent: true,
+        creator: 'Creator3',
+        genomeType: 'GenomeType3',
+        genomeVersion: 'GenomeVersion3',
+        idObject: 3,
+        publicOverlay: false,
+        order: 3,
+      },
+      {
+        name: 'Overlay2',
+        description: 'Description2',
+        type: 'Type2',
+        googleLicenseConsent: false,
+        creator: 'Creator2',
+        genomeType: 'GenomeType2',
+        genomeVersion: 'GenomeVersion2',
+        idObject: 2,
+        publicOverlay: true,
+        order: 2,
+      },
+    ];
+
+    const result = moveArrayElement(INPUT_ARRAY, 2, 1);
+
+    expect(result).toEqual(expectedResult);
+  });
+
+  it('should handle moving an element to the beginning of the array', () => {
+    const expectedResult: MapOverlay[] = [
+      {
+        name: 'Overlay3',
+        description: 'Description3',
+        type: 'Type3',
+        googleLicenseConsent: true,
+        creator: 'Creator3',
+        genomeType: 'GenomeType3',
+        genomeVersion: 'GenomeVersion3',
+        idObject: 3,
+        publicOverlay: false,
+        order: 3,
+      },
+      {
+        name: 'Overlay1',
+        description: 'Description1',
+        type: 'Type1',
+        googleLicenseConsent: true,
+        creator: 'Creator1',
+        genomeType: 'GenomeType1',
+        genomeVersion: 'GenomeVersion1',
+        idObject: 1,
+        publicOverlay: false,
+        order: 1,
+      },
+      {
+        name: 'Overlay2',
+        description: 'Description2',
+        type: 'Type2',
+        googleLicenseConsent: false,
+        creator: 'Creator2',
+        genomeType: 'GenomeType2',
+        genomeVersion: 'GenomeVersion2',
+        idObject: 2,
+        publicOverlay: true,
+        order: 2,
+      },
+    ];
+
+    const result = moveArrayElement(INPUT_ARRAY, 2, 0);
+
+    expect(result).toEqual(expectedResult);
+  });
+
+  it('should handle moving an element to the end of the array', () => {
+    const expectedResult: MapOverlay[] = [
+      {
+        name: 'Overlay2',
+        description: 'Description2',
+        type: 'Type2',
+        googleLicenseConsent: false,
+        creator: 'Creator2',
+        genomeType: 'GenomeType2',
+        genomeVersion: 'GenomeVersion2',
+        idObject: 2,
+        publicOverlay: true,
+        order: 2,
+      },
+      {
+        name: 'Overlay3',
+        description: 'Description3',
+        type: 'Type3',
+        googleLicenseConsent: true,
+        creator: 'Creator3',
+        genomeType: 'GenomeType3',
+        genomeVersion: 'GenomeVersion3',
+        idObject: 3,
+        publicOverlay: false,
+        order: 3,
+      },
+      {
+        name: 'Overlay1',
+        description: 'Description1',
+        type: 'Type1',
+        googleLicenseConsent: true,
+        creator: 'Creator1',
+        genomeType: 'GenomeType1',
+        genomeVersion: 'GenomeVersion1',
+        idObject: 1,
+        publicOverlay: false,
+        order: 1,
+      },
+    ];
+
+    const result = moveArrayElement(INPUT_ARRAY, 0, 2);
+
+    expect(result).toEqual(expectedResult);
+  });
+
+  it('should handle out-of-bounds indices gracefully', () => {
+    const result = moveArrayElement(INPUT_ARRAY, 5, 1);
+
+    expect(result).toEqual(INPUT_ARRAY);
+  });
+});
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.utils.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.utils.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1ce68cd3642b76b3c6e63657c40b024772a3f1b6
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/UserOverlaysWithoutGroup.utils.ts
@@ -0,0 +1,19 @@
+/* eslint-disable no-magic-numbers */
+import { MapOverlay } from '@/types/models';
+
+export const moveArrayElement = (
+  arr: MapOverlay[],
+  dragIndex: number,
+  hoverIndex: number,
+): MapOverlay[] => {
+  const arrayClone = [...arr];
+
+  const lastIndex = arr.length - 1;
+  if (hoverIndex > lastIndex || dragIndex > lastIndex) return arrayClone;
+
+  const [removedElement] = arrayClone.splice(dragIndex, 1);
+
+  arrayClone.splice(hoverIndex, 0, removedElement);
+
+  return arrayClone;
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/hooks/useUserOverlays.test.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/hooks/useUserOverlays.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..230d5c13df247dd24c121257ad495dfa93a908f3
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/hooks/useUserOverlays.test.ts
@@ -0,0 +1,204 @@
+/* eslint-disable no-magic-numbers */
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { renderHook, waitFor } from '@testing-library/react';
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { overlayFixture, overlaysFixture } from '@/models/fixtures/overlaysFixture';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { apiPath } from '@/redux/apiPath';
+import { HttpStatusCode } from 'axios';
+import { act } from 'react-dom/test-utils';
+import { OVERLAYS_INITIAL_STATE_MOCK } from '@/redux/overlays/overlays.mock';
+import { useUserOverlays } from './useUserOverlays';
+
+const mockedAxiosClient = mockNetworkResponse();
+
+describe('useUserOverlays', () => {
+  it('should fetch user overlays on mount if login exists', async () => {
+    mockedAxiosClient
+      .onGet(
+        apiPath.getAllUserOverlaysByCreatorQuery({
+          publicOverlay: false,
+          creator: 'test',
+        }),
+      )
+      .reply(HttpStatusCode.Ok, overlaysFixture);
+
+    const { Wrapper, store } = getReduxStoreWithActionsListener({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: OVERLAYS_INITIAL_STATE_MOCK,
+    });
+
+    renderHook(() => useUserOverlays(), {
+      wrapper: Wrapper,
+    });
+
+    const actions = store.getActions();
+    const firstAction = actions[0];
+
+    expect(firstAction.meta.arg).toBe('test');
+    expect(firstAction.type).toBe('overlays/getAllUserOverlaysByCreator/pending');
+
+    await waitFor(() => {
+      expect(actions[1].type).toBe('overlays/getAllUserOverlaysByCreator/fulfilled');
+    });
+  });
+  it('should not fetch user overlays on mount if login does not exist', async () => {
+    const { Wrapper, store } = getReduxStoreWithActionsListener({
+      user: {
+        authenticated: false,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: null,
+      },
+      overlays: OVERLAYS_INITIAL_STATE_MOCK,
+    });
+
+    const {
+      result: {
+        current: { userOverlaysList },
+      },
+    } = renderHook(() => useUserOverlays(), {
+      wrapper: Wrapper,
+    });
+
+    const actions = store.getActions();
+    const firstAction = actions[0];
+
+    expect(firstAction).toBeUndefined();
+    expect(userOverlaysList).toEqual([]);
+  });
+  it('should store fetched user overlays to userOverlaysList state', () => {
+    mockedAxiosClient
+      .onGet(
+        apiPath.getAllUserOverlaysByCreatorQuery({
+          publicOverlay: false,
+          creator: 'test',
+        }),
+      )
+      .reply(HttpStatusCode.Ok, overlaysFixture);
+
+    const { Wrapper } = getReduxStoreWithActionsListener({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: {
+        ...OVERLAYS_INITIAL_STATE_MOCK,
+        userOverlays: {
+          data: overlaysFixture,
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    const {
+      result: {
+        current: { userOverlaysList },
+      },
+    } = renderHook(() => useUserOverlays(), {
+      wrapper: Wrapper,
+    });
+
+    expect(userOverlaysList).toEqual(overlaysFixture);
+  });
+  it('should move user overlay list item on order change', async () => {
+    const FIRST_USER_OVERLAY = overlayFixture;
+    const SECOND_USER_OVERLAY = overlayFixture;
+    mockedAxiosClient
+      .onGet(
+        apiPath.getAllUserOverlaysByCreatorQuery({
+          publicOverlay: false,
+          creator: 'test',
+        }),
+      )
+      .reply(HttpStatusCode.Ok, [FIRST_USER_OVERLAY, SECOND_USER_OVERLAY]);
+
+    const { Wrapper } = getReduxStoreWithActionsListener({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: {
+        ...OVERLAYS_INITIAL_STATE_MOCK,
+        userOverlays: {
+          data: [FIRST_USER_OVERLAY, SECOND_USER_OVERLAY],
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    const {
+      result: {
+        current: { moveUserOverlayListItem, userOverlaysList },
+      },
+    } = renderHook(() => useUserOverlays(), {
+      wrapper: Wrapper,
+    });
+
+    await act(() => {
+      moveUserOverlayListItem(0, 1);
+    });
+
+    expect(userOverlaysList).toEqual([SECOND_USER_OVERLAY, FIRST_USER_OVERLAY]);
+  });
+  it('calls updateOverlays on calling updateUserOverlaysOrder', async () => {
+    const FIRST_USER_OVERLAY = { ...overlayFixture, order: 1, idObject: 12 };
+    const SECOND_USER_OVERLAY = { ...overlayFixture, order: 2, idObject: 92 };
+    mockedAxiosClient
+      .onGet(
+        apiPath.getAllUserOverlaysByCreatorQuery({
+          publicOverlay: false,
+          creator: 'test',
+        }),
+      )
+      .reply(HttpStatusCode.Ok, [FIRST_USER_OVERLAY, SECOND_USER_OVERLAY]);
+
+    const { Wrapper, store } = getReduxStoreWithActionsListener({
+      user: {
+        authenticated: true,
+        loading: 'succeeded',
+        error: DEFAULT_ERROR,
+        login: 'test',
+      },
+      overlays: {
+        ...OVERLAYS_INITIAL_STATE_MOCK,
+        userOverlays: {
+          data: [FIRST_USER_OVERLAY, SECOND_USER_OVERLAY],
+          loading: 'idle',
+          error: DEFAULT_ERROR,
+        },
+      },
+    });
+
+    const {
+      result: {
+        current: { moveUserOverlayListItem, updateUserOverlaysOrder },
+      },
+    } = renderHook(() => useUserOverlays(), {
+      wrapper: Wrapper,
+    });
+
+    await act(() => {
+      moveUserOverlayListItem(0, 1);
+    });
+
+    updateUserOverlaysOrder();
+
+    const actions = store.getActions();
+    expect(actions[1].type).toBe('overlays/getAllUserOverlaysByCreator/fulfilled');
+
+    const secondAction = actions[2];
+    expect(secondAction.type).toBe('overlays/updateOverlays/pending');
+  });
+});
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/hooks/useUserOverlays.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/hooks/useUserOverlays.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2fe3ee559c9022bf6c05bd336dccbba7c8ae8bc2
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/hooks/useUserOverlays.ts
@@ -0,0 +1,71 @@
+/* eslint-disable no-magic-numbers */
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import {
+  loadingUserOverlaysSelector,
+  userOverlaysDataSelector,
+} from '@/redux/overlays/overlays.selectors';
+import { getAllUserOverlaysByCreator, updateOverlays } from '@/redux/overlays/overlays.thunks';
+import { loginUserSelector } from '@/redux/user/user.selectors';
+import { MapOverlay } from '@/types/models';
+import { useEffect, useState } from 'react';
+import { moveArrayElement } from '../UserOverlaysWithoutGroup.utils';
+
+type UseUserOverlaysReturn = {
+  isPending: boolean;
+  userOverlaysList: MapOverlay[];
+  moveUserOverlayListItem: (dragIndex: number, hoverIndex: number) => void;
+  updateUserOverlaysOrder: () => void;
+};
+
+export const useUserOverlays = (): UseUserOverlaysReturn => {
+  const dispatch = useAppDispatch();
+  const login = useAppSelector(loginUserSelector);
+  const [userOverlaysList, setUserOverlaysList] = useState<MapOverlay[]>([]);
+  const userOverlays = useAppSelector(userOverlaysDataSelector);
+  const loadingUserOverlays = useAppSelector(loadingUserOverlaysSelector);
+  const isPending = loadingUserOverlays === 'pending';
+
+  useEffect(() => {
+    if (login) {
+      dispatch(getAllUserOverlaysByCreator(login));
+    }
+  }, [login, dispatch]);
+
+  useEffect(() => {
+    if (userOverlays) {
+      setUserOverlaysList(userOverlays);
+    }
+  }, [userOverlays]);
+
+  const moveUserOverlayListItem = (dragIndex: number, hoverIndex: number): void => {
+    const updatedUserOverlays = moveArrayElement(userOverlaysList, dragIndex, hoverIndex);
+    setUserOverlaysList(updatedUserOverlays);
+  };
+
+  const updateUserOverlaysOrder = (): void => {
+    const reorderedUserOverlays = [];
+    if (!userOverlays) return;
+
+    for (let index = 0; index < userOverlays.length; index += 1) {
+      const userOverlay = userOverlays[index];
+      const newOrderedUserOverlay = {
+        ...userOverlaysList[index],
+        order: index + 1,
+      };
+
+      if (userOverlay.idObject !== newOrderedUserOverlay.idObject) {
+        reorderedUserOverlays.push(newOrderedUserOverlay);
+      }
+    }
+
+    dispatch(updateOverlays(reorderedUserOverlays));
+  };
+
+  return {
+    moveUserOverlayListItem,
+    updateUserOverlaysOrder,
+    isPending,
+    userOverlaysList,
+  };
+};
diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/index.ts b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f8de206dcdfc757c2d7e20091aa14c03f835620f
--- /dev/null
+++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlays/UserOverlaysWithoutGroup/index.ts
@@ -0,0 +1 @@
+export { UserOverlaysWithoutGroup } from './UserOverlaysWithoutGroup.component';
diff --git a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/hooks/useEmptyBackground.test.ts b/src/components/Map/Drawer/OverlaysDrawer/hooks/useEmptyBackground.test.ts
similarity index 100%
rename from src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/hooks/useEmptyBackground.test.ts
rename to src/components/Map/Drawer/OverlaysDrawer/hooks/useEmptyBackground.test.ts
diff --git a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/hooks/useEmptyBackground.ts b/src/components/Map/Drawer/OverlaysDrawer/hooks/useEmptyBackground.ts
similarity index 100%
rename from src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/hooks/useEmptyBackground.ts
rename to src/components/Map/Drawer/OverlaysDrawer/hooks/useEmptyBackground.ts
diff --git a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/hooks/useOverlay.ts b/src/components/Map/Drawer/OverlaysDrawer/hooks/useOverlay.ts
similarity index 79%
rename from src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/hooks/useOverlay.ts
rename to src/components/Map/Drawer/OverlaysDrawer/hooks/useOverlay.ts
index d69c8df3d5755a839d24ef06a3cbca6f2d3f3e66..2016e292da4bb59d28659a4a0cff46535b1425a9 100644
--- a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/hooks/useOverlay.ts
+++ b/src/components/Map/Drawer/OverlaysDrawer/hooks/useOverlay.ts
@@ -6,10 +6,13 @@ import {
 } from '@/redux/overlayBioEntity/overlayBioEntity.selector';
 import { removeOverlayBioEntityForGivenOverlay } from '@/redux/overlayBioEntity/overlayBioEntity.slice';
 import { getOverlayBioEntityForAllModels } from '@/redux/overlayBioEntity/overlayBioEntity.thunk';
+import { BASE_API_URL } from '@/constants';
+import { apiPath } from '@/redux/apiPath';
 import { useEmptyBackground } from './useEmptyBackground';
 
 type UseOverlay = {
   toggleOverlay: () => void;
+  downloadOverlay: () => void;
   isOverlayActive: boolean;
   isOverlayLoading: boolean;
 };
@@ -29,5 +32,9 @@ export const useOverlay = (overlayId: number): UseOverlay => {
     }
   };
 
-  return { toggleOverlay, isOverlayActive, isOverlayLoading };
+  const downloadOverlay = (): void => {
+    window.open(`${BASE_API_URL}/${apiPath.downloadOverlay(overlayId)}`, '_blank');
+  };
+
+  return { toggleOverlay, isOverlayActive, isOverlayLoading, downloadOverlay };
 };
diff --git a/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.tsx b/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.tsx
index c0b7368f0b9ab106806ac58284a9e0a87f6f669d..96f3870a818b1b86b7f482c47b9cccafc7351982 100644
--- a/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.tsx
+++ b/src/components/Map/MapAdditionalActions/MapAdditionalActions.component.tsx
@@ -17,6 +17,7 @@ export const MapAdditionalActions = (): JSX.Element => {
         className="flex h-12 w-12 items-center justify-center rounded-full bg-white"
         onClick={zoomInToBioEntities}
         data-testid="location-button"
+        title="Center map"
       >
         <Icon className="h-[28px] w-[28px]" name="location" />
       </button>
@@ -26,6 +27,7 @@ export const MapAdditionalActions = (): JSX.Element => {
           className="flex h-12 w-12 items-center justify-center"
           onClick={zoomIn}
           data-testid="zoom-in-button"
+          title="Zoom in"
         >
           <Icon className="h-[24px] w-[24px]" name="magnifier-zoom-in" />
         </button>
@@ -35,6 +37,7 @@ export const MapAdditionalActions = (): JSX.Element => {
           className="flex h-12 w-12 items-center justify-center"
           onClick={zoomOut}
           data-testid="zoom-out-button"
+          title="Zoom out"
         >
           <Icon className="h-[24px] w-[24px]" name="magnifier-zoom-out" />
         </button>
diff --git a/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts
index 7d296729a6fde1d04dec7fa42f3b4f8a313b54a7..f711b392c959c975ed207dccd23b09365166ed6b 100644
--- a/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts
+++ b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.test.ts
@@ -6,6 +6,8 @@ import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreA
 import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { renderHook } from '@testing-library/react';
 import Map from 'ol/Map';
+import { initialMapDataFixture } from '@/redux/map/map.fixtures';
+import { modelsFixture } from '@/models/fixtures/modelsFixture';
 import { useAddtionalActions } from './useAdditionalActions';
 import { useVisibleBioEntitiesPolygonCoordinates } from './useVisibleBioEntitiesPolygonCoordinates';
 
@@ -122,8 +124,54 @@ describe('useAddtionalActions - hook', () => {
         useVisibleBioEntitiesPolygonCoordinatesMock.mockImplementation(() => undefined);
       });
 
-      it('should return undefined', () => {
-        const { Wrapper } = getReduxStoreWithActionsListener(INITIAL_STORE_STATE_MOCK);
+      it('should return undefined and center map by calculating coordinates when default center coordinates do not exist', () => {
+        const MAP_CONFIG = {
+          size: {
+            width: 3500,
+            height: 2000,
+          },
+          zoom: {
+            minZoom: 2,
+            maxZoom: 9,
+          },
+          position: {
+            x: 1300,
+            y: 1900,
+            z: 7,
+          },
+        };
+        const { Wrapper, store } = getReduxStoreWithActionsListener({
+          ...INITIAL_STORE_STATE_MOCK,
+          models: {
+            ...INITIAL_STORE_STATE_MOCK.models,
+            data: [
+              {
+                ...modelsFixture[0],
+                ...MAP_CONFIG.size,
+                ...MAP_CONFIG.zoom,
+                defaultCenterX: null,
+                defaultCenterY: null,
+                defaultZoomLevel: null,
+              },
+            ],
+          },
+          map: {
+            ...INITIAL_STORE_STATE_MOCK.map,
+            data: {
+              ...initialMapDataFixture,
+              position: {
+                last: MAP_CONFIG.position,
+                initial: MAP_CONFIG.position,
+              },
+              size: {
+                ...MAP_CONFIG.size,
+                ...MAP_CONFIG.zoom,
+                tileSize: 256,
+              },
+              modelId: modelsFixture[0].idObject,
+            },
+          },
+        });
         const {
           result: {
             current: { zoomInToBioEntities },
@@ -131,8 +179,81 @@ describe('useAddtionalActions - hook', () => {
         } = renderHook(() => useAddtionalActions(), {
           wrapper: Wrapper,
         });
+        const result = zoomInToBioEntities();
+        expect(result).toBeUndefined();
+        const actions = store.getActions();
+        const position = store.getState().map?.data.position;
+        expect(position?.last).toEqual(MAP_CONFIG.position);
+        expect(actions[0]).toEqual({
+          payload: { x: 1750, y: 1000, z: 5 },
+          type: 'map/setMapPosition',
+        });
+      });
 
-        expect(zoomInToBioEntities()).toBeUndefined();
+      it('should return undefined and center map using default center coordinates if exist', () => {
+        const MAP_CONFIG = {
+          size: {
+            width: 5000,
+            height: 10000,
+          },
+          zoom: {
+            minZoom: 2,
+            maxZoom: 9,
+          },
+          position: {
+            x: 1300,
+            y: 1900,
+            z: 7,
+          },
+        };
+        const { Wrapper, store } = getReduxStoreWithActionsListener({
+          ...INITIAL_STORE_STATE_MOCK,
+          models: {
+            ...INITIAL_STORE_STATE_MOCK.models,
+            data: [
+              {
+                ...modelsFixture[0],
+                ...MAP_CONFIG.size,
+                ...MAP_CONFIG.zoom,
+                defaultCenterX: 2500,
+                defaultCenterY: 5000,
+                defaultZoomLevel: 3,
+              },
+            ],
+          },
+          map: {
+            ...INITIAL_STORE_STATE_MOCK.map,
+            data: {
+              ...initialMapDataFixture,
+              position: {
+                last: MAP_CONFIG.position,
+                initial: MAP_CONFIG.position,
+              },
+              size: {
+                ...MAP_CONFIG.size,
+                ...MAP_CONFIG.zoom,
+                tileSize: 256,
+              },
+              modelId: modelsFixture[0].idObject,
+            },
+          },
+        });
+        const {
+          result: {
+            current: { zoomInToBioEntities },
+          },
+        } = renderHook(() => useAddtionalActions(), {
+          wrapper: Wrapper,
+        });
+        const result = zoomInToBioEntities();
+        expect(result).toBeUndefined();
+        const actions = store.getActions();
+        const position = store.getState().map?.data.position;
+        expect(position?.last).toEqual(MAP_CONFIG.position);
+        expect(actions[0]).toEqual({
+          payload: { x: 2500, y: 5000, z: 3 },
+          type: 'map/setMapPosition',
+        });
       });
     });
   });
diff --git a/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.ts b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.ts
index b93fc761920b36c99d3a51426a9bbed0f25f6512..bf0e8527932ebaa94cb138568d7bb984dfc67fe5 100644
--- a/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.ts
+++ b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.ts
@@ -1,9 +1,12 @@
-import { varyPositionZoom } from '@/redux/map/map.slice';
+import { setMapPosition, varyPositionZoom } from '@/redux/map/map.slice';
 import { SetBoundsResult, useSetBounds } from '@/utils/map/useSetBounds';
 import { useCallback } from 'react';
 import { useDispatch } from 'react-redux';
-import { MAP_ZOOM_IN_DELTA, MAP_ZOOM_OUT_DELTA } from '../MappAdditionalActions.constants';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { currentModelIdSelector, modelByIdSelector } from '@/redux/models/models.selectors';
+import { DEFAULT_ZOOM } from '@/constants/map';
 import { useVisibleBioEntitiesPolygonCoordinates } from './useVisibleBioEntitiesPolygonCoordinates';
+import { MAP_ZOOM_IN_DELTA, MAP_ZOOM_OUT_DELTA } from '../MappAdditionalActions.constants';
 
 interface UseAddtionalActionsResult {
   zoomIn(): void;
@@ -15,13 +18,26 @@ export const useAddtionalActions = (): UseAddtionalActionsResult => {
   const dispatch = useDispatch();
   const setBounds = useSetBounds();
   const polygonCoordinates = useVisibleBioEntitiesPolygonCoordinates();
+  const currentMapModelId = useAppSelector(currentModelIdSelector);
+  const currentModel = useAppSelector(state => modelByIdSelector(state, currentMapModelId));
 
   const zoomInToBioEntities = (): SetBoundsResult | undefined => {
-    if (!polygonCoordinates) {
-      return undefined;
+    if (polygonCoordinates) {
+      return setBounds(polygonCoordinates);
+    }
+
+    if (currentModel) {
+      const HALF = 2;
+      const defaultPosition = {
+        x: currentModel?.defaultCenterX ?? currentModel.width / HALF,
+        y: currentModel?.defaultCenterY ?? currentModel.height / HALF,
+        z: currentModel?.defaultZoomLevel ?? DEFAULT_ZOOM,
+      };
+
+      dispatch(setMapPosition(defaultPosition));
     }
 
-    return setBounds(polygonCoordinates);
+    return undefined;
   };
 
   const varyZoomByDelta = useCallback(
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..74f6839491421bf93129b446cc6d543636b7961f
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.test.ts
@@ -0,0 +1,91 @@
+import { LINE_WIDTH } from '@/constants/canvas';
+import { initialMapStateFixture } from '@/redux/map/map.fixtures';
+import { LinePoint } from '@/types/reactions';
+import { usePointToProjection } from '@/utils/map/usePointToProjection';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
+import { Feature } from 'ol';
+import { Geometry } from 'ol/geom';
+import { createOverlayLineFeature } from './createOverlayLineFeature';
+
+/* eslint-disable no-magic-numbers */
+const CASES: [LinePoint, number[]][] = [
+  [
+    [
+      { x: 0, y: 0 },
+      { x: 0, y: 0 },
+    ],
+    [0, 0, 0, 0],
+  ],
+  [
+    [
+      { x: 0, y: 0 },
+      { x: 100, y: 100 },
+    ],
+    [0, -238107693, Infinity, 0],
+  ],
+  [
+    [
+      { x: 100, y: 100 },
+      { x: 0, y: 0 },
+    ],
+    [0, -238107693, Infinity, 0],
+  ],
+  [
+    [
+      { x: 100, y: 0 },
+      { x: 0, y: 100 },
+    ],
+    [0, 0, 0, 0],
+  ],
+  [
+    [
+      { x: -50, y: 0 },
+      { x: 0, y: -50 },
+    ],
+    [0, 0, 0, 0],
+  ],
+];
+
+const COLOR = '#FFB3B3cc';
+
+const getFeature = (linePoint: LinePoint): Feature<Geometry> => {
+  const { Wrapper } = getReduxWrapperWithStore({
+    map: initialMapStateFixture,
+  });
+  const {
+    result: { current: pointToProjection },
+  } = renderHook(() => usePointToProjection(), {
+    wrapper: Wrapper,
+  });
+
+  return createOverlayLineFeature(linePoint, { pointToProjection, color: COLOR });
+};
+
+describe('createOverlayLineFeature - util', () => {
+  it.each(CASES)('should return Feature instance', linePoint => {
+    const feature = getFeature(linePoint);
+
+    expect(feature).toBeInstanceOf(Feature);
+  });
+
+  it.each(CASES)('should return Feature instance with valid style and stroke', linePoint => {
+    const feature = getFeature(linePoint);
+    const style = feature.getStyle();
+
+    expect(style).toMatchObject({
+      fill_: { color_: COLOR },
+      stroke_: {
+        color_: COLOR,
+        width_: LINE_WIDTH,
+      },
+    });
+  });
+
+  it.each(CASES)('should return Feature instance with valid geometry', (linePoint, extent) => {
+    const feature = getFeature(linePoint);
+    const geometry = feature.getGeometry();
+
+    expect(geometry?.getExtent()).toEqual(extent);
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b38d603bbb793c6578722f2c8170cd8f5c895b51
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.ts
@@ -0,0 +1,22 @@
+import { LinePoint } from '@/types/reactions';
+import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
+import { Feature } from 'ol';
+import { SimpleGeometry } from 'ol/geom';
+import { getLineFeature } from '../reactionsLayer/getLineFeature';
+import { getOverlayLineFeatureStyle } from './getOverlayLineFeatureStyle';
+
+interface Options {
+  color: string;
+  pointToProjection: UsePointToProjectionResult;
+}
+
+export const createOverlayLineFeature = (
+  points: LinePoint,
+  { color, pointToProjection }: Options,
+): Feature<SimpleGeometry> => {
+  const feature = getLineFeature(points, pointToProjection);
+
+  feature.setStyle(getOverlayLineFeatureStyle(color));
+
+  return feature;
+};
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..174c620d5c12b95a9033da7cf11a04a942302c91
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.test.ts
@@ -0,0 +1,27 @@
+import { LINE_WIDTH } from '@/constants/canvas';
+import { Fill, Stroke, Style } from 'ol/style';
+import { getOverlayLineFeatureStyle } from './getOverlayLineFeatureStyle';
+
+const COLORS = ['#000000', '#FFFFFF', '#F5F5F5', '#C0C0C0', '#C0C0C0aa', '#C0C0C0bb'];
+
+describe('getOverlayLineFeatureStyle - util', () => {
+  it.each(COLORS)('should return Style object', color => {
+    const result = getOverlayLineFeatureStyle(color);
+    expect(result).toBeInstanceOf(Style);
+  });
+
+  it.each(COLORS)('should set valid color values for Fill', color => {
+    const result = getOverlayLineFeatureStyle(color);
+    const fill = result.getFill();
+    expect(fill).toBeInstanceOf(Fill);
+    expect(fill?.getColor()).toBe(color);
+  });
+
+  it.each(COLORS)('should set valid color values for Fill', color => {
+    const result = getOverlayLineFeatureStyle(color);
+    const stroke = result.getStroke();
+    expect(stroke).toBeInstanceOf(Stroke);
+    expect(stroke?.getColor()).toBe(color);
+    expect(stroke?.getWidth()).toBe(LINE_WIDTH);
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.ts
new file mode 100644
index 0000000000000000000000000000000000000000..407c2416bbcee994a3d954d866520e0f2d65064c
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.ts
@@ -0,0 +1,5 @@
+import { LINE_WIDTH } from '@/constants/canvas';
+import { Fill, Stroke, Style } from 'ol/style';
+
+export const getOverlayLineFeatureStyle = (color: string): Style =>
+  new Style({ fill: new Fill({ color }), stroke: new Stroke({ color, width: LINE_WIDTH }) });
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.test.ts
index b580a998904b2975b82c0a527aa805c748c38288..61841611e83b4818cf7c1382cc0ff8795e85996e 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.test.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.test.ts
@@ -1,7 +1,7 @@
-import { renderHook } from '@testing-library/react';
-import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { CONFIGURATION_INITIAL_STORE_MOCKS } from '@/redux/configuration/configuration.mock';
 import { OverlayBioEntityRender } from '@/types/OLrendering';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
 import { useGetOverlayColor } from './useGetOverlayColor';
 
 describe('useOverlayFeatures - hook', () => {
@@ -20,6 +20,7 @@ describe('useOverlayFeatures - hook', () => {
 
   describe('getOverlayBioEntityColorByAvailableProperties - function', () => {
     const ENTITY: OverlayBioEntityRender = {
+      type: 'rectangle',
       id: 0,
       modelId: 0,
       x1: 0,
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.test.ts
index 19c9b309415c6943c7c86e8b1fe477c606affe81..15c9cf3e5e9820d3d3f9d604bc19a7e5dad1c383 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.test.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.test.ts
@@ -1,11 +1,11 @@
 /* eslint-disable no-magic-numbers */
-import { renderHook } from '@testing-library/react';
-import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { CONFIGURATION_INITIAL_STORE_MOCKS } from '@/redux/configuration/configuration.mock';
-import { OVERLAYS_PUBLIC_FETCHED_STATE_MOCK } from '@/redux/overlays/overlays.mock';
 import { mapStateWithCurrentlySelectedMainMapFixture } from '@/redux/map/map.fixtures';
 import { MODELS_DATA_MOCK_WITH_MAIN_MAP } from '@/redux/models/models.mock';
 import { MOCKED_OVERLAY_BIO_ENTITY_RENDER } from '@/redux/overlayBioEntity/overlayBioEntity.mock';
+import { OVERLAYS_PUBLIC_FETCHED_STATE_MOCK } from '@/redux/overlays/overlays.mock';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
 import { useOverlayFeatures } from './useOverlayFeatures';
 
 /**
@@ -52,7 +52,9 @@ describe('useOverlayFeatures', () => {
       wrapper: Wrapper,
     });
 
-    expect(features).toHaveLength(6);
+    expect(features).toHaveLength(10);
+
+    // type: rectangle
     expect(features[0].getGeometry()?.getCoordinates()).toEqual([
       [
         [-13149141, 18867005],
@@ -65,5 +67,19 @@ describe('useOverlayFeatures', () => {
     // eslint-disable-next-line @typescript-eslint/ban-ts-comment
     // @ts-ignore
     expect(features[0].getStyle().getFill().getColor()).toBe('#FFFFFFcc');
+
+    // type: line
+    expect(features[7].getGeometry()?.getCoordinates()).toEqual([
+      [
+        [-13149141, 18867005],
+        [-13149141, 18881970],
+        [-13141659, 18881970],
+        [-13141659, 18867005],
+        [-13149141, 18867005],
+      ],
+    ]);
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore
+    expect(features[7].getStyle().getFill().getColor()).toBe('#ff0000cc');
   });
 });
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts
index 06985195eb9dafe82dbf23f616b3214945c9aff2..477a95dd324f06f8099d88db81055e7324b77d5f 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts
@@ -1,18 +1,21 @@
-import { useMemo } from 'react';
-import { usePointToProjection } from '@/utils/map/usePointToProjection';
-import type Feature from 'ol/Feature';
-import type Polygon from 'ol/geom/Polygon';
 import { ZERO } from '@/constants/common';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import {
   getOverlayOrderSelector,
   overlayBioEntitiesForCurrentModelSelector,
 } from '@/redux/overlayBioEntity/overlayBioEntity.selector';
+import { LinePoint } from '@/types/reactions';
+import { usePointToProjection } from '@/utils/map/usePointToProjection';
+import type Feature from 'ol/Feature';
+import { SimpleGeometry } from 'ol/geom';
+import type Polygon from 'ol/geom/Polygon';
+import { useMemo } from 'react';
 import { createOverlayGeometryFeature } from './createOverlayGeometryFeature';
+import { createOverlayLineFeature } from './createOverlayLineFeature';
 import { getPolygonLatitudeCoordinates } from './getPolygonLatitudeCoordinates';
 import { useGetOverlayColor } from './useGetOverlayColor';
 
-export const useOverlayFeatures = (): Feature<Polygon>[] => {
+export const useOverlayFeatures = (): Feature<Polygon>[] | Feature<SimpleGeometry>[] => {
   const pointToProjection = usePointToProjection();
   const { getOverlayBioEntityColorByAvailableProperties } = useGetOverlayColor();
   const overlaysOrder = useAppSelector(getOverlayOrderSelector);
@@ -34,12 +37,27 @@ export const useOverlayFeatures = (): Feature<Polygon>[] => {
             overlaysOrder.find(({ id }) => id === entity.overlayId)?.index || ZERO,
         });
 
-        return createOverlayGeometryFeature(
+        const color = getOverlayBioEntityColorByAvailableProperties(entity);
+
+        if (entity.type === 'rectangle') {
+          return createOverlayGeometryFeature(
+            [
+              ...pointToProjection({ x: xMin, y: entity.y1 }),
+              ...pointToProjection({ x: xMax, y: entity.y2 }),
+            ],
+            color,
+          );
+        }
+
+        return createOverlayLineFeature(
           [
-            ...pointToProjection({ x: xMin, y: entity.y1 }),
-            ...pointToProjection({ x: xMax, y: entity.y2 }),
-          ],
-          getOverlayBioEntityColorByAvailableProperties(entity),
+            { x: entity.x1, y: entity.y1 },
+            { x: entity.x2, y: entity.y2 },
+          ] as LinePoint,
+          {
+            color,
+            pointToProjection,
+          },
         );
       }),
     [overlaysOrder, bioEntities, pointToProjection, getOverlayBioEntityColorByAvailableProperties],
diff --git a/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.ts b/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.ts
index 40211171605c35ff87995e6ed9abf02bc300c76b..b7ce166ad5bf96b39976fc6d08fabb8fae5e6f1a 100644
--- a/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.ts
+++ b/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.ts
@@ -1,12 +1,12 @@
 import { LinePoint } from '@/types/reactions';
 import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
 import { Feature } from 'ol';
-import { LineString } from 'ol/geom';
+import { LineString, SimpleGeometry } from 'ol/geom';
 
 export const getLineFeature = (
   linePoints: LinePoint,
   pointToProjection: UsePointToProjectionResult,
-): Feature => {
+): Feature<SimpleGeometry> => {
   const points = linePoints.map(pointToProjection);
 
   return new Feature({
diff --git a/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.test.ts b/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.test.ts
index 3ab05530b0776d285bb698ea023174f678521398..295b91d1aad607f60565dbb88c33f6bc043659a0 100644
--- a/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.test.ts
+++ b/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.test.ts
@@ -50,7 +50,7 @@ describe('onMapPositionChange - util', () => {
       {
         x: 1479,
         y: 581,
-        z: 7,
+        z: 6.68620779943448,
       },
     ],
   ];
diff --git a/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.ts b/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.ts
index 8bdf55b6e8614a029db153428d9f7defd248b114..7102fec7fdecfd1f771295030dd82e30c42bc767 100644
--- a/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.ts
+++ b/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.ts
@@ -18,7 +18,7 @@ export const onMapPositionChange =
         setMapPosition({
           x,
           y,
-          z: Math.round(zoom),
+          z: zoom,
         }),
       );
     };
diff --git a/src/components/SPA/MinervaSPA.component.tsx b/src/components/SPA/MinervaSPA.component.tsx
index 5d0d77ae259b644fe129036bd5bdb759fb3b9b52..5762a59b846afa2583c0454ef3fcef59d036fddb 100644
--- a/src/components/SPA/MinervaSPA.component.tsx
+++ b/src/components/SPA/MinervaSPA.component.tsx
@@ -3,6 +3,8 @@ import { Map } from '@/components/Map';
 import { manrope } from '@/constants/font';
 import { useReduxBusQueryManager } from '@/utils/query-manager/useReduxBusQueryManager';
 import { twMerge } from 'tailwind-merge';
+import { useEffect } from 'react';
+import { PluginsManager } from '@/services/pluginsManager';
 import { useInitializeStore } from '../../utils/initialize/useInitializeStore';
 import { Modal } from '../FunctionalArea/Modal';
 import { ContextMenu } from '../FunctionalArea/ContextMenu';
@@ -12,6 +14,12 @@ export const MinervaSPA = (): JSX.Element => {
   useInitializeStore();
   useReduxBusQueryManager();
 
+  useEffect(() => {
+    const unsubscribe = PluginsManager.init();
+
+    return () => unsubscribe();
+  }, []);
+
   return (
     <div className={twMerge('relative', manrope.variable)}>
       <FunctionalArea />
diff --git a/src/models/compartmentPathwaySchema.ts b/src/models/compartmentPathwaySchema.ts
index b7f3cdc4e4939565b564c4961086db3f26879bd1..368ff17fc1f0fc77251f2bec1b917ec1f44c2858 100644
--- a/src/models/compartmentPathwaySchema.ts
+++ b/src/models/compartmentPathwaySchema.ts
@@ -1,3 +1,4 @@
+/* eslint-disable no-magic-numbers */
 import { z } from 'zod';
 
 export const compartmentPathwaySchema = z.object({
@@ -34,7 +35,7 @@ export const compartmentPathwayDetailsSchema = z.object({
   hierarchyVisibilityLevel: z.string(),
   homomultimer: z.null(),
   hypothetical: z.null(),
-  id: z.number(),
+  id: z.number().gt(-1),
   initialAmount: z.null(),
   initialConcentration: z.null(),
   linkedSubmodel: z.null(),
diff --git a/src/models/exportSchema.ts b/src/models/exportSchema.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1e01113d88696d3fb4c79183d6d29a1b5c37f869
--- /dev/null
+++ b/src/models/exportSchema.ts
@@ -0,0 +1,5 @@
+import { z } from 'zod';
+
+export const exportNetworkchema = z.string();
+
+export const exportElementsSchema = z.string();
diff --git a/src/models/fixtures/configurationFixture.ts b/src/models/fixtures/configurationFixture.ts
index 56e19f7adcb59678ca144fd6a63bb741c8e51876..c27f2840b8ae3a037decb1b48dd99cce790a3d21 100644
--- a/src/models/fixtures/configurationFixture.ts
+++ b/src/models/fixtures/configurationFixture.ts
@@ -5,5 +5,5 @@ import { configurationSchema } from '../configurationSchema';
 
 export const configurationFixture = createFixture(configurationSchema, {
   seed: ZOD_SEED,
-  array: { min: 1, max: 1 },
+  array: { min: 3, max: 3 },
 });
diff --git a/src/models/fixtures/overlayBioEntityFixture.ts b/src/models/fixtures/overlayBioEntityFixture.ts
index da0c6da654ba996874863860034ebf6856762054..4cdeaebfde4d08c304d56de8d8db889a385b7c85 100644
--- a/src/models/fixtures/overlayBioEntityFixture.ts
+++ b/src/models/fixtures/overlayBioEntityFixture.ts
@@ -2,9 +2,21 @@ import { ZOD_SEED } from '@/constants';
 import { z } from 'zod';
 // eslint-disable-next-line import/no-extraneous-dependencies
 import { createFixture } from 'zod-fixture';
-import { overlayBioEntitySchema } from '../overlayBioEntitySchema';
+import {
+  overlayBioEntitySchema,
+  overlayElementWithBioEntitySchema,
+  overlayElementWithReactionSchema,
+} from '../overlayBioEntitySchema';
 
 export const overlayBioEntityFixture = createFixture(z.array(overlayBioEntitySchema), {
   seed: ZOD_SEED,
   array: { min: 3, max: 3 },
 });
+
+export const overlayElementWithReactionFixture = createFixture(overlayElementWithReactionSchema, {
+  seed: ZOD_SEED,
+});
+
+export const overlayElementWithBioEntityFixture = createFixture(overlayElementWithBioEntitySchema, {
+  seed: ZOD_SEED,
+});
diff --git a/src/models/fixtures/pluginFixture.ts b/src/models/fixtures/pluginFixture.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9e1d83f8fe79ef99b8f6326fb1f392387752e884
--- /dev/null
+++ b/src/models/fixtures/pluginFixture.ts
@@ -0,0 +1,8 @@
+import { ZOD_SEED } from '@/constants';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { createFixture } from 'zod-fixture';
+import { pluginSchema } from '../pluginSchema';
+
+export const pluginFixture = createFixture(pluginSchema, {
+  seed: ZOD_SEED,
+});
diff --git a/src/models/mocks/configurationFormatsMock.ts b/src/models/mocks/configurationFormatsMock.ts
index 8d6d4e8afa75491a2fcafee702da4320a633f1b9..34ec36a2e7bc287f63d45eef763b1c0b22c21637 100644
--- a/src/models/mocks/configurationFormatsMock.ts
+++ b/src/models/mocks/configurationFormatsMock.ts
@@ -29,3 +29,23 @@ export const CONFIGURATION_FORMATS_MOCK: ConfigurationFormatSchema[] = [
     extension: 'gpml',
   },
 ];
+
+export const CONFIGURATION_IMAGE_FORMATS_TYPES_MOCK: string[] = ['PNG image', 'PDF', 'SVG image'];
+
+export const CONFIGURATION_IMAGE_FORMATS_MOCK: ConfigurationFormatSchema[] = [
+  {
+    name: 'PNG image',
+    handler: 'lcsb.mapviewer.converter.graphics.PngImageGenerator',
+    extension: 'png',
+  },
+  {
+    name: 'PDF',
+    handler: 'lcsb.mapviewer.converter.graphics.PdfImageGenerator',
+    extension: 'pdf',
+  },
+  {
+    name: 'SVG image',
+    handler: 'lcsb.mapviewer.converter.graphics.SvgImageGenerator',
+    extension: 'svg',
+  },
+];
diff --git a/src/models/mocks/pluginsMock.ts b/src/models/mocks/pluginsMock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f5c91eafdb32833dff36caedddfc4b85d9bac2f6
--- /dev/null
+++ b/src/models/mocks/pluginsMock.ts
@@ -0,0 +1,44 @@
+import { MinervaPlugin } from '@/types/models';
+
+export const PLUGINS_MOCK: MinervaPlugin[] = [
+  {
+    hash: '5e3fcb59588cc311ef9839feea6382eb',
+    name: 'Disease-variant associations',
+    version: '1.0.0',
+    isPublic: true,
+    isDefault: false,
+    urls: ['https://minerva-service.lcsb.uni.lu/plugins/disease-associations/plugin.js'],
+  },
+  {
+    hash: '20df86476c311824bbfe73d1034af89e',
+    name: 'GSEA',
+    version: '0.9.2',
+    isPublic: true,
+    isDefault: false,
+    urls: ['https://minerva-service.lcsb.uni.lu/plugins/gsea/plugin.js'],
+  },
+  {
+    hash: '5314b9f996e56e67f0dad65e7df8b73b',
+    name: 'PD map guide',
+    version: '1.0.2',
+    isPublic: true,
+    isDefault: false,
+    urls: ['https://minerva-service.lcsb.uni.lu/plugins/guide/plugin.js'],
+  },
+  {
+    hash: 'b85ae2f4cd67736489b5fd2b635b1013',
+    name: 'Map exploation',
+    version: '1.0.0',
+    isPublic: true,
+    isDefault: false,
+    urls: ['https://minerva-service.lcsb.uni.lu/plugins/exploration/plugin.js'],
+  },
+  {
+    hash: '77c32edf387652dfaad8a20f2a0ce76b',
+    name: 'Drug reactions',
+    version: '1.0.0',
+    isPublic: true,
+    isDefault: false,
+    urls: ['https://minerva-service.lcsb.uni.lu/plugins/drug-reactions/plugin.js'],
+  },
+];
diff --git a/src/models/overlayBioEntitySchema.ts b/src/models/overlayBioEntitySchema.ts
index d9dd58950b85a6d21bdde12e38e668af4d9b30e4..ffa8f5847d578da84236314ce036d5bc425d123c 100644
--- a/src/models/overlayBioEntitySchema.ts
+++ b/src/models/overlayBioEntitySchema.ts
@@ -1,8 +1,19 @@
 import { z } from 'zod';
 import { overlayLeftBioEntitySchema } from './overlayLeftBioEntitySchema';
+import { overlayLeftReactionSchema } from './overlayLeftReactionSchema';
 import { overlayRightBioEntitySchema } from './overlayRightBioEntitySchema';
 
-export const overlayBioEntitySchema = z.object({
+export const overlayElementWithBioEntitySchema = z.object({
   left: overlayLeftBioEntitySchema,
   right: overlayRightBioEntitySchema,
 });
+
+export const overlayElementWithReactionSchema = z.object({
+  left: overlayLeftReactionSchema,
+  right: overlayRightBioEntitySchema,
+});
+
+export const overlayBioEntitySchema = z.union([
+  overlayElementWithBioEntitySchema,
+  overlayElementWithReactionSchema,
+]);
diff --git a/src/models/overlayLeftReactionSchema.ts b/src/models/overlayLeftReactionSchema.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c47febcff7136233ac38e7d4c41c6eb3d85c2144
--- /dev/null
+++ b/src/models/overlayLeftReactionSchema.ts
@@ -0,0 +1,34 @@
+import { z } from 'zod';
+import { lineSchema } from './lineSchema';
+import { reactionProduct } from './reactionProduct';
+import { referenceSchema } from './referenceSchema';
+
+export const overlayLeftReactionSchema = z.object({
+  id: z.number(),
+  notes: z.string(),
+  idReaction: z.string(),
+  name: z.string(),
+  reversible: z.boolean(),
+  symbol: z.null(),
+  abbreviation: z.null(),
+  formula: z.null(),
+  mechanicalConfidenceScore: z.null(),
+  lowerBound: z.null(),
+  upperBound: z.null(),
+  subsystem: z.null(),
+  geneProteinReaction: z.null(),
+  visibilityLevel: z.string(),
+  z: z.number(),
+  synonyms: z.array(z.unknown()),
+  model: z.number(),
+  kinetics: z.null(),
+  line: lineSchema,
+  processCoordinates: z.null(),
+  stringType: z.string(),
+  modifiers: z.array(reactionProduct),
+  reactants: z.array(reactionProduct),
+  products: z.array(reactionProduct),
+  elementId: z.string(),
+  operators: z.array(z.unknown()),
+  references: z.array(referenceSchema),
+});
diff --git a/src/models/pluginSchema.ts b/src/models/pluginSchema.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2cfb0725fc31a652b5db6d5e38996002eb262af9
--- /dev/null
+++ b/src/models/pluginSchema.ts
@@ -0,0 +1,11 @@
+/* eslint-disable no-magic-numbers */
+import { z } from 'zod';
+
+export const pluginSchema = z.object({
+  hash: z.string(),
+  name: z.string(),
+  version: z.string(),
+  isPublic: z.boolean(),
+  isDefault: z.boolean(),
+  urls: z.array(z.string().min(1)),
+});
diff --git a/src/models/reactionProduct.ts b/src/models/reactionProduct.ts
new file mode 100644
index 0000000000000000000000000000000000000000..96905877910e382f1736d595351286f5fa636807
--- /dev/null
+++ b/src/models/reactionProduct.ts
@@ -0,0 +1,9 @@
+import { z } from 'zod';
+import { lineSchema } from './lineSchema';
+
+export const reactionProduct = z.object({
+  id: z.number(),
+  line: lineSchema,
+  stoichiometry: z.null(),
+  element: z.number(),
+});
diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts
index 7dd6cac479e541a068318ab6fc143d683f371026..ac815f25ece6507d4ad61f5ebc2a8bc87dc6e1f9 100644
--- a/src/redux/apiPath.ts
+++ b/src/redux/apiPath.ts
@@ -1,6 +1,6 @@
 import { PROJECT_ID } from '@/constants';
-import { PerfectSearchParams } from '@/types/search';
 import { Point } from '@/types/map';
+import { PerfectSearchParams } from '@/types/search';
 import { GetPublicationsParams, PublicationsQueryParams } from './publications/publications.types';
 
 const getPublicationsURLSearchParams = (
@@ -61,6 +61,22 @@ export const apiPath = {
   getCompartmentPathwayDetails: (ids: number[]): string =>
     `projects/${PROJECT_ID}/models/*/bioEntities/elements/?id=${ids.join(',')}`,
   sendCompartmentPathwaysIds: (): string => `projects/${PROJECT_ID}/models/*/bioEntities/elements/`,
+  downloadNetworkCsv: (): string =>
+    `projects/${PROJECT_ID}/models/*/bioEntities/reactions/:downloadCsv`,
+  getAllUserOverlaysByCreatorQuery: ({
+    publicOverlay,
+    creator,
+  }: {
+    publicOverlay: boolean;
+    creator: string;
+  }): string =>
+    `projects/${PROJECT_ID}/overlays/?creator=${creator}&publicOverlay=${String(publicOverlay)}`,
+  updateOverlay: (overlayId: number): string => `projects/${PROJECT_ID}/overlays/${overlayId}/`,
+  removeOverlay: (overlayId: number): string => `projects/pdmap_appu_test/overlays/${overlayId}/`,
+  downloadElementsCsv: (): string =>
+    `projects/${PROJECT_ID}/models/*/bioEntities/elements/:downloadCsv`,
+  downloadOverlay: (overlayId: number): string =>
+    `projects/${PROJECT_ID}/overlays/${overlayId}:downloadSource`,
   getSourceFile: (): string => `/projects/${PROJECT_ID}:downloadSource`,
   getMesh: (meshId: string): string => `mesh/${meshId}`,
   getTaxonomy: (taxonomyId: string): string => `taxonomy/${taxonomyId}`,
@@ -68,4 +84,7 @@ export const apiPath = {
     `/projects/${PROJECT_ID}/models/${modelId}/publications/?${getPublicationsURLSearchParams(
       params,
     )}`,
+  registerPluign: (): string => `plugins/`,
+  getPlugin: (pluginId: string): string => `plugins/${pluginId}/`,
+  getAllPlugins: (): string => `/plugins/`,
 };
diff --git a/src/redux/backgrounds/background.selectors.ts b/src/redux/backgrounds/background.selectors.ts
index b8443ab5545da2f894ca43fe284669b56fcdf038..b815cf59b879e5cf3460cbeb092bef85612ae065 100644
--- a/src/redux/backgrounds/background.selectors.ts
+++ b/src/redux/backgrounds/background.selectors.ts
@@ -1,12 +1,12 @@
-import { createSelector } from '@reduxjs/toolkit';
 import { EMPTY_BACKGROUND_NAME } from '@/constants/backgrounds';
+import { createSelector } from '@reduxjs/toolkit';
 import { mapDataSelector } from '../map/map.selectors';
 import { rootSelector } from '../root/root.selectors';
 
 export const backgroundsSelector = createSelector(rootSelector, state => state.backgrounds);
 
 export const backgroundsDataSelector = createSelector(backgroundsSelector, backgrounds => {
-  return backgrounds.data;
+  return backgrounds?.data || [];
 });
 
 const MAIN_BACKGROUND = 0;
diff --git a/src/redux/configuration/configuration.constants.ts b/src/redux/configuration/configuration.constants.ts
index 56448d47fce6e44bf31adfe19acd78b25b340453..bcf3c906f5ab72e0012749ad77fe2d710e2cd866 100644
--- a/src/redux/configuration/configuration.constants.ts
+++ b/src/redux/configuration/configuration.constants.ts
@@ -15,3 +15,7 @@ export const GPML_HANDLER_NAME_ID = 'GPML';
 export const SBML_HANDLER_NAME_ID = 'SBML';
 export const CELL_DESIGNER_SBML_HANDLER_NAME_ID = 'CellDesigner SBML';
 export const SBGN_ML_HANDLER_NAME_ID = 'SBGN-ML';
+
+export const PNG_IMAGE_HANDLER_NAME_ID = 'PNG image';
+export const PDF_HANDLER_NAME_ID = 'PDF';
+export const SVG_IMAGE_HANDLER_NAME_ID = 'SVG image';
diff --git a/src/redux/configuration/configuration.selectors.ts b/src/redux/configuration/configuration.selectors.ts
index 451590bbca72cf44ab73bec01501175c15f96612..25cbfbfa134c8e574480d310a96781e7bd0cc776 100644
--- a/src/redux/configuration/configuration.selectors.ts
+++ b/src/redux/configuration/configuration.selectors.ts
@@ -10,11 +10,14 @@ import {
   MIN_COLOR_VAL_NAME_ID,
   NEUTRAL_COLOR_VAL_NAME_ID,
   OVERLAY_OPACITY_NAME_ID,
+  PDF_HANDLER_NAME_ID,
+  PNG_IMAGE_HANDLER_NAME_ID,
   SBGN_ML_HANDLER_NAME_ID,
   SBML_HANDLER_NAME_ID,
   SIMPLE_COLOR_VAL_NAME_ID,
+  SVG_IMAGE_HANDLER_NAME_ID,
 } from './configuration.constants';
-import { ConfigurationHandlersIds } from './configuration.types';
+import { ConfigurationHandlersIds, ConfigurationImageHandlersIds } from './configuration.types';
 
 const configurationSelector = createSelector(rootSelector, state => state.configuration);
 const configurationOptionsSelector = createSelector(configurationSelector, state => state.options);
@@ -63,7 +66,7 @@ export const modelFormatsSelector = createSelector(
   state => state?.modelFormats,
 );
 
-export const formatsEntriesSelector = createSelector(
+export const modelFormatsEntriesSelector = createSelector(
   modelFormatsSelector,
   (modelFormats): Record<string, ConfigurationFormatSchema> => {
     return Object.fromEntries(
@@ -78,7 +81,7 @@ export const formatsEntriesSelector = createSelector(
 );
 
 export const formatsHandlersSelector = createSelector(
-  formatsEntriesSelector,
+  modelFormatsEntriesSelector,
   (formats): ConfigurationHandlersIds => {
     return {
       [GPML_HANDLER_NAME_ID]: formats[GPML_HANDLER_NAME_ID]?.handler,
@@ -88,3 +91,38 @@ export const formatsHandlersSelector = createSelector(
     };
   },
 );
+
+export const imageFormatsSelector = createSelector(
+  configurationMainSelector,
+  state => state?.imageFormats,
+);
+
+export const imageFormatsEntriesSelector = createSelector(
+  imageFormatsSelector,
+  (modelFormats): Record<string, ConfigurationFormatSchema> => {
+    return Object.fromEntries(
+      (modelFormats || []).flat().map((format: ConfigurationFormatSchema) => [format.name, format]),
+    );
+  },
+);
+
+export const imageHandlersSelector = createSelector(
+  imageFormatsEntriesSelector,
+  (formats): ConfigurationImageHandlersIds => {
+    return {
+      [PNG_IMAGE_HANDLER_NAME_ID]: formats[PNG_IMAGE_HANDLER_NAME_ID]?.handler,
+      [PDF_HANDLER_NAME_ID]: formats[PDF_HANDLER_NAME_ID]?.handler,
+      [SVG_IMAGE_HANDLER_NAME_ID]: formats[SVG_IMAGE_HANDLER_NAME_ID]?.handler,
+    };
+  },
+);
+
+export const miramiTypesSelector = createSelector(
+  configurationMainSelector,
+  state => state?.miriamTypes,
+);
+
+export const loadingConfigurationMainSelector = createSelector(
+  configurationSelector,
+  state => state?.main?.loading,
+);
diff --git a/src/redux/configuration/configuration.types.ts b/src/redux/configuration/configuration.types.ts
index e797b88764723d2f18b1c2c7b2898c46d3ade799..343c8b86557ada9505aa50413a2b109b2e367569 100644
--- a/src/redux/configuration/configuration.types.ts
+++ b/src/redux/configuration/configuration.types.ts
@@ -3,8 +3,11 @@ import { Configuration } from '@/types/models';
 import {
   CELL_DESIGNER_SBML_HANDLER_NAME_ID,
   GPML_HANDLER_NAME_ID,
+  PDF_HANDLER_NAME_ID,
+  PNG_IMAGE_HANDLER_NAME_ID,
   SBGN_ML_HANDLER_NAME_ID,
   SBML_HANDLER_NAME_ID,
+  SVG_IMAGE_HANDLER_NAME_ID,
 } from './configuration.constants';
 
 export type ConfigurationMainState = FetchDataState<Configuration>;
@@ -15,3 +18,9 @@ export interface ConfigurationHandlersIds {
   [CELL_DESIGNER_SBML_HANDLER_NAME_ID]?: string;
   [SBGN_ML_HANDLER_NAME_ID]?: string;
 }
+
+export interface ConfigurationImageHandlersIds {
+  [PNG_IMAGE_HANDLER_NAME_ID]?: string;
+  [PDF_HANDLER_NAME_ID]?: string;
+  [SVG_IMAGE_HANDLER_NAME_ID]?: string;
+}
diff --git a/src/redux/export/export.mock.ts b/src/redux/export/export.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c17abce73156f1eb8a1ea32c3fda8d2e9fef392f
--- /dev/null
+++ b/src/redux/export/export.mock.ts
@@ -0,0 +1,18 @@
+import { ExportState } from './export.types';
+
+export const EXPORT_INITIAL_STATE_MOCK: ExportState = {
+  downloadNetwork: {
+    error: {
+      message: '',
+      name: '',
+    },
+    loading: 'idle',
+  },
+  downloadElements: {
+    error: {
+      message: '',
+      name: '',
+    },
+    loading: 'idle',
+  },
+};
diff --git a/src/redux/export/export.reducers.test.ts b/src/redux/export/export.reducers.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..894ee98a802339b948da3a12556716284b4aa41d
--- /dev/null
+++ b/src/redux/export/export.reducers.test.ts
@@ -0,0 +1,148 @@
+import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
+import {
+  ToolkitStoreWithSingleSlice,
+  createStoreInstanceUsingSliceReducer,
+} from '@/utils/createStoreInstanceUsingSliceReducer';
+import { HttpStatusCode } from 'axios';
+import { ExportState } from './export.types';
+import exportReducer from './export.slice';
+import { apiPath } from '../apiPath';
+import { downloadNetwork, downloadElements } from './export.thunks';
+
+const mockedAxiosClient = mockNetworkNewAPIResponse();
+
+const INITIAL_STATE: ExportState = {
+  downloadNetwork: {
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
+  downloadElements: {
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
+};
+
+describe('export reducer', () => {
+  global.URL.createObjectURL = jest.fn();
+  let store = {} as ToolkitStoreWithSingleSlice<ExportState>;
+  beforeEach(() => {
+    store = createStoreInstanceUsingSliceReducer('export', exportReducer);
+  });
+
+  it('should match initial state', () => {
+    const action = { type: 'unknown' };
+    expect(exportReducer(undefined, action)).toEqual(INITIAL_STATE);
+  });
+
+  it('should update store after successful downloadNetwork query', async () => {
+    mockedAxiosClient.onPost(apiPath.downloadNetworkCsv()).reply(HttpStatusCode.Ok, 'test');
+    await store.dispatch(
+      downloadNetwork({
+        annotations: [],
+        columns: [],
+        excludedCompartmentIds: [],
+        includedCompartmentIds: [],
+        submaps: [],
+      }),
+    );
+    const { loading } = store.getState().export.downloadNetwork;
+
+    expect(loading).toEqual('succeeded');
+  });
+
+  it('should update store on loading downloadNetwork query', async () => {
+    mockedAxiosClient.onPost(apiPath.downloadNetworkCsv()).reply(HttpStatusCode.Ok, 'test');
+    const downloadNetworkPromise = store.dispatch(
+      downloadNetwork({
+        annotations: [],
+        columns: [],
+        excludedCompartmentIds: [],
+        includedCompartmentIds: [],
+        submaps: [],
+      }),
+    );
+
+    const { loading } = store.getState().export.downloadNetwork;
+    expect(loading).toEqual('pending');
+
+    await downloadNetworkPromise;
+
+    const { loading: promiseFulfilled } = store.getState().export.downloadNetwork;
+
+    expect(promiseFulfilled).toEqual('succeeded');
+  });
+
+  it('should update store after failed downloadNetwork query', async () => {
+    mockedAxiosClient
+      .onPost(apiPath.downloadNetworkCsv())
+      .reply(HttpStatusCode.NotFound, undefined);
+    await store.dispatch(
+      downloadNetwork({
+        annotations: [],
+        columns: [],
+        excludedCompartmentIds: [],
+        includedCompartmentIds: [],
+        submaps: [],
+      }),
+    );
+    const { loading } = store.getState().export.downloadNetwork;
+
+    expect(loading).toEqual('failed');
+  });
+
+  it('should update store after successful downloadElements query', async () => {
+    mockedAxiosClient.onPost(apiPath.downloadElementsCsv()).reply(HttpStatusCode.Ok, 'test');
+    await store.dispatch(
+      downloadElements({
+        annotations: [],
+        columns: [],
+        excludedCompartmentIds: [],
+        includedCompartmentIds: [],
+        submaps: [],
+      }),
+    );
+    const { loading } = store.getState().export.downloadElements;
+
+    expect(loading).toEqual('succeeded');
+  });
+
+  it('should update store on loading downloadElements query', async () => {
+    mockedAxiosClient.onPost(apiPath.downloadElementsCsv()).reply(HttpStatusCode.Ok, 'test');
+    const downloadElementsPromise = store.dispatch(
+      downloadElements({
+        annotations: [],
+        columns: [],
+        excludedCompartmentIds: [],
+        includedCompartmentIds: [],
+        submaps: [],
+      }),
+    );
+
+    const { loading } = store.getState().export.downloadElements;
+    expect(loading).toEqual('pending');
+
+    await downloadElementsPromise;
+
+    const { loading: promiseFulfilled } = store.getState().export.downloadElements;
+
+    expect(promiseFulfilled).toEqual('succeeded');
+  });
+
+  it('should update store after failed downloadElements query', async () => {
+    mockedAxiosClient
+      .onPost(apiPath.downloadElementsCsv())
+      .reply(HttpStatusCode.NotFound, undefined);
+    await store.dispatch(
+      downloadElements({
+        annotations: [],
+        columns: [],
+        excludedCompartmentIds: [],
+        includedCompartmentIds: [],
+        submaps: [],
+      }),
+    );
+    const { loading } = store.getState().export.downloadElements;
+
+    expect(loading).toEqual('failed');
+  });
+});
diff --git a/src/redux/export/export.reducers.ts b/src/redux/export/export.reducers.ts
new file mode 100644
index 0000000000000000000000000000000000000000..39ea3df45651233260da3b6b1603ce18abf33fa0
--- /dev/null
+++ b/src/redux/export/export.reducers.ts
@@ -0,0 +1,28 @@
+import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
+import { downloadNetwork, downloadElements } from './export.thunks';
+import { ExportState } from './export.types';
+
+export const downloadNetworkReducer = (builder: ActionReducerMapBuilder<ExportState>): void => {
+  builder.addCase(downloadNetwork.pending, state => {
+    state.downloadNetwork.loading = 'pending';
+  });
+  builder.addCase(downloadNetwork.fulfilled, state => {
+    state.downloadNetwork.loading = 'succeeded';
+  });
+  builder.addCase(downloadNetwork.rejected, state => {
+    state.downloadNetwork.loading = 'failed';
+  });
+};
+
+export const downloadElementsReducer = (builder: ActionReducerMapBuilder<ExportState>): void => {
+  builder.addCase(downloadElements.pending, state => {
+    state.downloadElements.loading = 'pending';
+  });
+  builder.addCase(downloadElements.fulfilled, state => {
+    state.downloadElements.loading = 'succeeded';
+  });
+  builder.addCase(downloadElements.rejected, state => {
+    state.downloadElements.loading = 'failed';
+    // TODO to discuss manage state of failure
+  });
+};
diff --git a/src/redux/export/export.slice.ts b/src/redux/export/export.slice.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5b0774dd52b3c1ce33507be9366ff636425c02ed
--- /dev/null
+++ b/src/redux/export/export.slice.ts
@@ -0,0 +1,32 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { ExportState } from './export.types';
+import { downloadNetworkReducer, downloadElementsReducer } from './export.reducers';
+
+const initialState: ExportState = {
+  downloadNetwork: {
+    error: {
+      message: '',
+      name: '',
+    },
+    loading: 'idle',
+  },
+  downloadElements: {
+    error: {
+      message: '',
+      name: '',
+    },
+    loading: 'idle',
+  },
+};
+
+const exportSlice = createSlice({
+  name: 'export',
+  initialState,
+  reducers: {},
+  extraReducers: builder => {
+    downloadNetworkReducer(builder);
+    downloadElementsReducer(builder);
+  },
+});
+
+export default exportSlice.reducer;
diff --git a/src/redux/export/export.thunks.test.ts b/src/redux/export/export.thunks.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..baad92cad09cdd06c7b68b7e3929a0d89780bcbe
--- /dev/null
+++ b/src/redux/export/export.thunks.test.ts
@@ -0,0 +1,99 @@
+import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
+import { HttpStatusCode } from 'axios';
+import {
+  ToolkitStoreWithSingleSlice,
+  createStoreInstanceUsingSliceReducer,
+} from '@/utils/createStoreInstanceUsingSliceReducer';
+import { apiPath } from '../apiPath';
+import { ExportState } from './export.types';
+import exportReducer from './export.slice';
+import { downloadNetwork, downloadElements } from './export.thunks';
+
+const mockedAxiosClient = mockNetworkNewAPIResponse();
+
+describe('export thunks', () => {
+  let store = {} as ToolkitStoreWithSingleSlice<ExportState>;
+  beforeEach(() => {
+    store = createStoreInstanceUsingSliceReducer('export', exportReducer);
+
+    global.URL.createObjectURL = jest.fn();
+    global.document.body.appendChild = jest.fn();
+  });
+  describe('downloadNetwork', () => {
+    beforeEach(() => {
+      jest.clearAllMocks();
+    });
+    it('should download file when data response from API is valid', async () => {
+      mockedAxiosClient.onPost(apiPath.downloadNetworkCsv()).reply(HttpStatusCode.Ok, 'test');
+
+      await store.dispatch(
+        downloadNetwork({
+          annotations: [],
+          columns: [],
+          excludedCompartmentIds: [],
+          includedCompartmentIds: [],
+          submaps: [],
+        }),
+      );
+      expect(global.URL.createObjectURL).toHaveBeenCalledWith(new Blob(['test']));
+
+      expect(global.document.body.appendChild).toHaveBeenCalled();
+    });
+    it('should not download file when data response from API is not valid', async () => {
+      mockedAxiosClient
+        .onPost(apiPath.downloadNetworkCsv())
+        .reply(HttpStatusCode.NotFound, undefined);
+
+      await store.dispatch(
+        downloadNetwork({
+          annotations: [],
+          columns: [],
+          excludedCompartmentIds: [],
+          includedCompartmentIds: [],
+          submaps: [],
+        }),
+      );
+
+      expect(global.document.body.appendChild).not.toHaveBeenCalled();
+    });
+  });
+
+  describe('downloadElements', () => {
+    beforeEach(() => {
+      jest.clearAllMocks();
+    });
+    it('should download file when data response from API is valid', async () => {
+      mockedAxiosClient.onPost(apiPath.downloadElementsCsv()).reply(HttpStatusCode.Ok, 'test');
+
+      await store.dispatch(
+        downloadElements({
+          annotations: [],
+          columns: [],
+          excludedCompartmentIds: [],
+          includedCompartmentIds: [],
+          submaps: [],
+        }),
+      );
+      expect(global.URL.createObjectURL).toHaveBeenCalledWith(new Blob(['test']));
+
+      expect(global.document.body.appendChild).toHaveBeenCalled();
+    });
+    it('should not download file when data response from API is not valid', async () => {
+      mockedAxiosClient
+        .onPost(apiPath.downloadElementsCsv())
+        .reply(HttpStatusCode.NotFound, undefined);
+
+      await store.dispatch(
+        downloadElements({
+          annotations: [],
+          columns: [],
+          excludedCompartmentIds: [],
+          includedCompartmentIds: [],
+          submaps: [],
+        }),
+      );
+
+      expect(global.document.body.appendChild).not.toHaveBeenCalled();
+    });
+  });
+});
diff --git a/src/redux/export/export.thunks.ts b/src/redux/export/export.thunks.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3a25cd8c40f76e9442d43fa354bd7877d29b4306
--- /dev/null
+++ b/src/redux/export/export.thunks.ts
@@ -0,0 +1,63 @@
+/* eslint-disable no-magic-numbers */
+import { axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance';
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { PROJECT_ID } from '@/constants';
+import { ExportNetwork, ExportElements } from '@/types/models';
+import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+import { exportNetworkchema, exportElementsSchema } from '@/models/exportSchema';
+import { apiPath } from '../apiPath';
+import { downloadFileFromBlob } from './export.utils';
+
+type DownloadElementsBodyRequest = {
+  columns: string[];
+  submaps: number[];
+  annotations: string[];
+  includedCompartmentIds: number[];
+  excludedCompartmentIds: number[];
+};
+
+export const downloadElements = createAsyncThunk(
+  'export/downloadElements',
+  async (data: DownloadElementsBodyRequest): Promise<void> => {
+    const response = await axiosInstanceNewAPI.post<ExportElements>(
+      apiPath.downloadElementsCsv(),
+      data,
+      {
+        withCredentials: true,
+      },
+    );
+
+    const isDataValid = validateDataUsingZodSchema(response.data, exportElementsSchema);
+
+    if (isDataValid) {
+      downloadFileFromBlob(response.data, `${PROJECT_ID}-elementExport.csv`);
+    }
+  },
+);
+
+type DownloadNetworkBodyRequest = {
+  columns: string[];
+  submaps: number[];
+  annotations: string[];
+  includedCompartmentIds: number[];
+  excludedCompartmentIds: number[];
+};
+
+export const downloadNetwork = createAsyncThunk(
+  'export/downloadNetwork',
+  async (data: DownloadNetworkBodyRequest): Promise<void> => {
+    const response = await axiosInstanceNewAPI.post<ExportNetwork>(
+      apiPath.downloadNetworkCsv(),
+      data,
+      {
+        withCredentials: true,
+      },
+    );
+
+    const isDataValid = validateDataUsingZodSchema(response.data, exportNetworkchema);
+
+    if (isDataValid) {
+      downloadFileFromBlob(response.data, `${PROJECT_ID}-networkExport.csv`);
+    }
+  },
+);
diff --git a/src/redux/export/export.types.ts b/src/redux/export/export.types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cf53310214bbb1713690081f292f9c85284c5291
--- /dev/null
+++ b/src/redux/export/export.types.ts
@@ -0,0 +1,12 @@
+import { Loading } from '@/types/loadingState';
+
+export type ExportState = {
+  downloadNetwork: {
+    loading: Loading;
+    error: Error;
+  };
+  downloadElements: {
+    loading: Loading;
+    error: Error;
+  };
+};
diff --git a/src/redux/export/export.utils.ts b/src/redux/export/export.utils.ts
new file mode 100644
index 0000000000000000000000000000000000000000..60cba1fd90f1fe16a31e44a266f7bc8dd41206a6
--- /dev/null
+++ b/src/redux/export/export.utils.ts
@@ -0,0 +1,9 @@
+export const downloadFileFromBlob = (data: string, filename: string): void => {
+  const url = window.URL.createObjectURL(new Blob([data]));
+  const link = document.createElement('a');
+  link.href = url;
+  link.setAttribute('download', filename);
+  document.body.appendChild(link);
+  link.click();
+  link.remove();
+};
diff --git a/src/redux/modal/modal.constants.ts b/src/redux/modal/modal.constants.ts
index 8d8f27bd056e1fb05496918ffe10dc64725a3cb5..f0df9964801af60a083ceb6a773b4a7c8375c40f 100644
--- a/src/redux/modal/modal.constants.ts
+++ b/src/redux/modal/modal.constants.ts
@@ -11,4 +11,5 @@ export const MODAL_INITIAL_STATE: ModalState = {
   molArtState: {
     uniprotId: MOL_ART_UNIPROT_ID_DEFAULT,
   },
+  editOverlayState: null,
 };
diff --git a/src/redux/modal/modal.mock.ts b/src/redux/modal/modal.mock.ts
index 47c46050e50f3f1c4c1257ab11c6aee3315f0fec..22b833031510bdea484a479d1fc43faa52c66c74 100644
--- a/src/redux/modal/modal.mock.ts
+++ b/src/redux/modal/modal.mock.ts
@@ -11,4 +11,5 @@ export const MODAL_INITIAL_STATE_MOCK: ModalState = {
   molArtState: {
     uniprotId: MOL_ART_UNIPROT_ID_DEFAULT,
   },
+  editOverlayState: null,
 };
diff --git a/src/redux/modal/modal.reducers.ts b/src/redux/modal/modal.reducers.ts
index 7b1581806cf4062d447c6c3a3d9e32286f5655df..2cda42b432235ac40f371a35be3f93fe6629f653 100644
--- a/src/redux/modal/modal.reducers.ts
+++ b/src/redux/modal/modal.reducers.ts
@@ -1,6 +1,6 @@
 import { ModalName } from '@/types/modal';
 import { PayloadAction } from '@reduxjs/toolkit';
-import { ModalState } from './modal.types';
+import { ModalState, OpenEditOverlayModalAction } from './modal.types';
 
 export const openModalReducer = (state: ModalState, action: PayloadAction<ModalName>): void => {
   state.isOpen = true;
@@ -56,3 +56,13 @@ export const openPublicationsModalReducer = (state: ModalState): void => {
   state.modalName = 'publications';
   state.modalTitle = 'Publications';
 };
+
+export const openEditOverlayModalReducer = (
+  state: ModalState,
+  action: OpenEditOverlayModalAction,
+): void => {
+  state.isOpen = true;
+  state.modalName = 'edit-overlay';
+  state.modalTitle = action.payload.name;
+  state.editOverlayState = action.payload;
+};
diff --git a/src/redux/modal/modal.selector.ts b/src/redux/modal/modal.selector.ts
index 3ac54031a23b84c37876e56b2b8b6820da8a6203..c77223ea30f739d335170d382c9ecb524b6b6a49 100644
--- a/src/redux/modal/modal.selector.ts
+++ b/src/redux/modal/modal.selector.ts
@@ -15,3 +15,8 @@ export const currentSelectedBioEntityIdSelector = createSelector(
   modalSelector,
   modal => modal?.molArtState.uniprotId || MOL_ART_UNIPROT_ID_DEFAULT,
 );
+
+export const currentEditedOverlaySelector = createSelector(
+  modalSelector,
+  modal => modal.editOverlayState,
+);
diff --git a/src/redux/modal/modal.slice.ts b/src/redux/modal/modal.slice.ts
index a324db237e715053968b125448f9048234da523e..75de9c430304b2829e30352a9ffb1561cb39336e 100644
--- a/src/redux/modal/modal.slice.ts
+++ b/src/redux/modal/modal.slice.ts
@@ -8,6 +8,7 @@ import {
   openMolArtModalByIdReducer,
   setOverviewImageIdReducer,
   openPublicationsModalReducer,
+  openEditOverlayModalReducer,
 } from './modal.reducers';
 
 const modalSlice = createSlice({
@@ -21,6 +22,7 @@ const modalSlice = createSlice({
     setOverviewImageId: setOverviewImageIdReducer,
     openLoginModal: openLoginModalReducer,
     openPublicationsModal: openPublicationsModalReducer,
+    openEditOverlayModal: openEditOverlayModalReducer,
   },
 });
 
@@ -32,6 +34,7 @@ export const {
   openMolArtModalById,
   openLoginModal,
   openPublicationsModal,
+  openEditOverlayModal,
 } = modalSlice.actions;
 
 export default modalSlice.reducer;
diff --git a/src/redux/modal/modal.types.ts b/src/redux/modal/modal.types.ts
index a6ddf286297afd30e9c97a00edb1b531ad5fccf1..dfb5ca5d5c5a1f7b020b766bed4b7602e9cc2526 100644
--- a/src/redux/modal/modal.types.ts
+++ b/src/redux/modal/modal.types.ts
@@ -1,4 +1,6 @@
 import { ModalName } from '@/types/modal';
+import { MapOverlay } from '@/types/models';
+import { PayloadAction } from '@reduxjs/toolkit';
 
 export type OverviewImagesModalState = {
   imageId?: number;
@@ -8,10 +10,17 @@ export type MolArtModalState = {
   uniprotId?: string | undefined;
 };
 
+export type EditOverlayState = MapOverlay | null;
+
 export interface ModalState {
   isOpen: boolean;
   modalName: ModalName;
   modalTitle: string;
   overviewImagesState: OverviewImagesModalState;
   molArtState: MolArtModalState;
+  editOverlayState: EditOverlayState;
 }
+
+export type OpenEditOverlayModalPayload = MapOverlay;
+
+export type OpenEditOverlayModalAction = PayloadAction<OpenEditOverlayModalPayload>;
diff --git a/src/redux/models/models.selectors.ts b/src/redux/models/models.selectors.ts
index f078c75776c7b9148fc23c94ac1464780638ac82..99d94b7648a22f1d07d77ac63cdf69592d55c0f9 100644
--- a/src/redux/models/models.selectors.ts
+++ b/src/redux/models/models.selectors.ts
@@ -45,6 +45,9 @@ export const modelByIdSelector = createSelector(
 
 const MAIN_MAP = 0;
 export const mainMapModelSelector = createSelector(modelsDataSelector, models => models[MAIN_MAP]);
+
+export const loadingModelsSelector = createSelector(modelsSelector, state => state.loading);
+
 export const mainMapModelDescriptionSelector = createSelector(
   modelsDataSelector,
   models => models[MAIN_MAP].description,
diff --git a/src/redux/overlayBioEntity/overlayBioEntity.mock.ts b/src/redux/overlayBioEntity/overlayBioEntity.mock.ts
index 84fab91d714d1acdbb49aa3275b6b5fe13cc668c..9b093c3eeaecee77b8fc2923f37f8cd3da8c5eec 100644
--- a/src/redux/overlayBioEntity/overlayBioEntity.mock.ts
+++ b/src/redux/overlayBioEntity/overlayBioEntity.mock.ts
@@ -8,6 +8,7 @@ export const OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK: OverlaysBioEntityState = {
 
 export const MOCKED_OVERLAY_BIO_ENTITY_RENDER: OverlayBioEntityRender[] = [
   {
+    type: 'rectangle',
     id: 1,
     modelId: 52,
     width: 30,
@@ -21,6 +22,7 @@ export const MOCKED_OVERLAY_BIO_ENTITY_RENDER: OverlayBioEntityRender[] = [
     color: null,
   },
   {
+    type: 'rectangle',
     id: 2,
     modelId: 52,
     width: 30,
@@ -34,6 +36,7 @@ export const MOCKED_OVERLAY_BIO_ENTITY_RENDER: OverlayBioEntityRender[] = [
     color: null,
   },
   {
+    type: 'rectangle',
     id: 3,
     modelId: 52,
     width: 40,
@@ -46,4 +49,32 @@ export const MOCKED_OVERLAY_BIO_ENTITY_RENDER: OverlayBioEntityRender[] = [
     value: null,
     color: { rgb: -65536, alpha: 0 },
   },
+  {
+    type: 'line',
+    id: 66143,
+    modelId: 52,
+    x1: 4462.61826820353,
+    x2: 4571.99387254902,
+    y1: 7105.89040426431,
+    y2: 6979.823529411765,
+    width: 109.3756043454905,
+    height: 126.06687485254497,
+    value: null,
+    overlayId: 20,
+    color: null,
+  },
+  {
+    type: 'line',
+    id: 66144,
+    modelId: 52,
+    x1: 4454.850442288663,
+    x2: 4463.773636826477,
+    y1: 7068.434324866321,
+    y2: 7112.188429617157,
+    width: 8.923194537814197,
+    height: 43.75410475083663,
+    value: null,
+    overlayId: 20,
+    color: null,
+  },
 ];
diff --git a/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts b/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts
index 8a09ebb08aca68fb46d2bb1a908fceb45c41bd56..555c1c87e768169ccba7b2454b313314320c7c9d 100644
--- a/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts
+++ b/src/redux/overlayBioEntity/overlayBioEntity.thunk.ts
@@ -25,6 +25,9 @@ export const getOverlayBioEntity = createAsyncThunk(
   }: GetOverlayBioEntityThunkProps): Promise<OverlayBioEntityRender[] | undefined> => {
     const response = await axiosInstanceNewAPI.get<OverlayBioEntity[]>(
       apiPath.getOverlayBioEntity({ overlayId, modelId }),
+      {
+        withCredentials: true,
+      },
     );
 
     const validOverlayBioEntities = getValidOverlayBioEntities(response.data);
diff --git a/src/redux/overlayBioEntity/overlayBioEntity.utils.ts b/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
index 7c92f7a20080e78660bcf391194990c13940451b..6656d725badcafef167e19d63226804077ca4a21 100644
--- a/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
+++ b/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
@@ -2,6 +2,8 @@ import { ONE } from '@/constants/common';
 import { overlayBioEntitySchema } from '@/models/overlayBioEntitySchema';
 import { OverlayBioEntityRender } from '@/types/OLrendering';
 import { OverlayBioEntity } from '@/types/models';
+import { getOverlayReactionCoordsFromLine } from '@/utils/overlays/getOverlayReactionCoords';
+import { isBioEntity, isReaction } from '@/utils/overlays/overlaysElementsTypeGuards';
 import { z } from 'zod';
 
 export const parseOverlayBioEntityToOlRenderingFormat = (
@@ -9,8 +11,16 @@ export const parseOverlayBioEntityToOlRenderingFormat = (
   overlayId: number,
 ): OverlayBioEntityRender[] =>
   data.reduce((acc: OverlayBioEntityRender[], entity: OverlayBioEntity) => {
-    if (entity.left.x && entity.left.y) {
+    /**
+     * The're two types of entities - bioentity and reaction
+     * Bioentity comes with the single only element
+     * And reaction comes with many different lines that needs to be merged together
+     * Every reaction line is a different entity after reduce
+     */
+
+    if (isBioEntity(entity)) {
       acc.push({
+        type: 'rectangle',
         id: entity.left.id,
         modelId: entity.left.model,
         x1: entity.left.x,
@@ -24,6 +34,31 @@ export const parseOverlayBioEntityToOlRenderingFormat = (
         color: entity.right.color,
       });
     }
+
+    if (isReaction(entity)) {
+      const { products, reactants, modifiers } = entity.left;
+      const lines = [products, reactants, modifiers].flat().map(element => element.line);
+      const coords = lines.map(getOverlayReactionCoordsFromLine).flat();
+      const elements = coords.map(
+        ({ x1, x2, y1, y2, id, width, height }): OverlayBioEntityRender => ({
+          type: 'line',
+          id,
+          modelId: entity.left.model,
+          x1,
+          x2,
+          y1,
+          y2,
+          width,
+          height: Math.abs(height),
+          value: entity.right.value,
+          overlayId,
+          color: entity.right.color,
+        }),
+      );
+
+      acc.push(...elements);
+    }
+
     return acc;
   }, []);
 
diff --git a/src/redux/overlays/overlays.mock.ts b/src/redux/overlays/overlays.mock.ts
index 3e1557ba4e7604dd58aa294eeba2bd13ebced06e..7942bb040427bcc40b158893a6abab60cbdd27e8 100644
--- a/src/redux/overlays/overlays.mock.ts
+++ b/src/redux/overlays/overlays.mock.ts
@@ -10,6 +10,19 @@ export const OVERLAYS_INITIAL_STATE_MOCK: OverlaysState = {
     loading: 'idle',
     error: DEFAULT_ERROR,
   },
+  userOverlays: {
+    data: [],
+    loading: 'idle',
+    error: DEFAULT_ERROR,
+  },
+  updateOverlays: {
+    loading: 'idle',
+    error: DEFAULT_ERROR,
+  },
+  removeOverlay: {
+    loading: 'idle',
+    error: DEFAULT_ERROR,
+  },
 };
 
 export const PUBLIC_OVERLAYS_MOCK: MapOverlay[] = [
@@ -85,6 +98,19 @@ export const OVERLAYS_PUBLIC_FETCHED_STATE_MOCK: OverlaysState = {
     loading: 'idle',
     error: DEFAULT_ERROR,
   },
+  userOverlays: {
+    data: [],
+    loading: 'idle',
+    error: DEFAULT_ERROR,
+  },
+  updateOverlays: {
+    loading: 'idle',
+    error: DEFAULT_ERROR,
+  },
+  removeOverlay: {
+    loading: 'idle',
+    error: DEFAULT_ERROR,
+  },
 };
 
 export const ADD_OVERLAY_MOCK = {
diff --git a/src/redux/overlays/overlays.reducers.test.ts b/src/redux/overlays/overlays.reducers.test.ts
index 2fe92673346f59194fc6f78a5a85443d31d0b273..90ee7771f73590345e165b792ac9ad5cfd2385f8 100644
--- a/src/redux/overlays/overlays.reducers.test.ts
+++ b/src/redux/overlays/overlays.reducers.test.ts
@@ -3,6 +3,7 @@ import { PROJECT_ID } from '@/constants';
 import {
   createdOverlayFileFixture,
   createdOverlayFixture,
+  overlayFixture,
   overlaysFixture,
   uploadedOverlayFileContentFixture,
 } from '@/models/fixtures/overlaysFixture';
@@ -15,7 +16,13 @@ import { HttpStatusCode } from 'axios';
 import { waitFor } from '@testing-library/react';
 import { apiPath } from '../apiPath';
 import overlaysReducer from './overlays.slice';
-import { addOverlay, getAllPublicOverlaysByProjectId } from './overlays.thunks';
+import {
+  addOverlay,
+  getAllPublicOverlaysByProjectId,
+  getAllUserOverlaysByCreator,
+  removeOverlay,
+  updateOverlays,
+} from './overlays.thunks';
 import { OverlaysState } from './overlays.types';
 import { ADD_OVERLAY_MOCK } from './overlays.mock';
 
@@ -29,6 +36,19 @@ const INITIAL_STATE: OverlaysState = {
     loading: 'idle',
     error: { name: '', message: '' },
   },
+  userOverlays: {
+    data: [],
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
+  updateOverlays: {
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
+  removeOverlay: {
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
 };
 
 describe('overlays reducer', () => {
@@ -142,4 +162,133 @@ describe('overlays reducer', () => {
 
     expect(loading).toEqual('failed');
   });
+
+  it('should update store when getAllUserOverlaysByCreator is pending', async () => {
+    mockedAxiosClient
+      .onGet(apiPath.getAllUserOverlaysByCreatorQuery({ creator: 'test', publicOverlay: false }))
+      .reply(HttpStatusCode.Ok, overlaysFixture);
+
+    await store.dispatch(getAllUserOverlaysByCreator('test'));
+    const { loading } = store.getState().overlays.userOverlays;
+
+    waitFor(() => {
+      expect(loading).toEqual('pending');
+    });
+  });
+
+  it('should update store after successful getAllUserOverlaysByCreator', async () => {
+    mockedAxiosClient
+      .onGet(apiPath.getAllUserOverlaysByCreatorQuery({ creator: 'test', publicOverlay: false }))
+      .reply(HttpStatusCode.Ok, overlaysFixture);
+
+    const getUserOverlaysPromise = store.dispatch(getAllUserOverlaysByCreator('test'));
+    const { loading } = store.getState().overlays.userOverlays;
+    expect(loading).toBe('pending');
+
+    await getUserOverlaysPromise;
+
+    const { loading: loadingFulfilled, error } = store.getState().overlays.userOverlays;
+    expect(loadingFulfilled).toEqual('succeeded');
+    expect(error).toEqual({ message: '', name: '' });
+  });
+  it('should update store after failed getAllUserOverlaysByCreator', async () => {
+    mockedAxiosClient
+      .onGet(apiPath.getAllUserOverlaysByCreatorQuery({ creator: 'test', publicOverlay: false }))
+      .reply(HttpStatusCode.NotFound, {});
+
+    await store.dispatch(getAllUserOverlaysByCreator('test'));
+    const { loading } = store.getState().overlays.userOverlays;
+    expect(loading).toEqual('failed');
+  });
+
+  it('should update store when updateOverlay is pending', async () => {
+    mockedAxiosClient
+      .onPatch(apiPath.updateOverlay(overlayFixture.idObject))
+      .reply(HttpStatusCode.Ok, overlayFixture);
+
+    store.dispatch(updateOverlays([overlayFixture]));
+    const { loading } = store.getState().overlays.updateOverlays;
+    expect(loading).toBe('pending');
+  });
+
+  it('should update store after successful updateOverlay', async () => {
+    mockedAxiosClient
+      .onPatch(apiPath.updateOverlay(overlayFixture.idObject))
+      .reply(HttpStatusCode.Ok, overlayFixture);
+
+    const updateUserOverlaysPromise = store.dispatch(updateOverlays([overlayFixture]));
+    const { loading } = store.getState().overlays.updateOverlays;
+    expect(loading).toBe('pending');
+
+    await updateUserOverlaysPromise;
+
+    const { loading: loadingFulfilled, error } = store.getState().overlays.updateOverlays;
+    expect(loadingFulfilled).toEqual('succeeded');
+    expect(error).toEqual({ message: '', name: '' });
+  });
+  it('should update store after failed updateOverlay', async () => {
+    mockedAxiosClient
+      .onPatch(apiPath.updateOverlay(overlayFixture.idObject))
+      .reply(HttpStatusCode.NotFound, {});
+
+    await store.dispatch(updateOverlays([overlayFixture]));
+
+    const { loading } = store.getState().overlays.updateOverlays;
+    expect(loading).toEqual('failed');
+  });
+
+  it('should update store when removeOverlay is pending', async () => {
+    mockedAxiosClient
+      .onDelete(apiPath.removeOverlay(overlayFixture.idObject))
+      .reply(HttpStatusCode.Ok, {});
+
+    store.dispatch(
+      removeOverlay({
+        login: 'test',
+        overlayId: overlayFixture.idObject,
+      }),
+    );
+    const { loading } = store.getState().overlays.removeOverlay;
+    expect(loading).toBe('pending');
+  });
+
+  it('should update store after successful removeOverlay', async () => {
+    mockedAxiosClient
+      .onDelete(apiPath.removeOverlay(overlayFixture.idObject))
+      .reply(HttpStatusCode.Ok, {});
+
+    const removeUserOverlaysPromise = store.dispatch(
+      removeOverlay({
+        login: 'test',
+        overlayId: overlayFixture.idObject,
+      }),
+    );
+    const { loading } = store.getState().overlays.removeOverlay;
+    expect(loading).toBe('pending');
+
+    await removeUserOverlaysPromise;
+
+    const { loading: loadingFulfilled, error } = store.getState().overlays.removeOverlay;
+    expect(loadingFulfilled).toEqual('succeeded');
+    expect(error).toEqual({ message: '', name: '' });
+  });
+  it('should update store after failed removeOverlay', async () => {
+    mockedAxiosClient
+      .onDelete(apiPath.removeOverlay(overlayFixture.idObject))
+      .reply(HttpStatusCode.NotFound, {});
+
+    const removeUserOverlaysPromise = store.dispatch(
+      removeOverlay({
+        login: 'test',
+        overlayId: overlayFixture.idObject,
+      }),
+    );
+    const { loading } = store.getState().overlays.removeOverlay;
+    expect(loading).toBe('pending');
+
+    await removeUserOverlaysPromise;
+
+    const { loading: loadingRejected } = store.getState().overlays.removeOverlay;
+    expect(loadingRejected).toEqual('failed');
+  });
 });
diff --git a/src/redux/overlays/overlays.reducers.ts b/src/redux/overlays/overlays.reducers.ts
index d8f12eef16e426ef9c7aef040030fd20963a1842..50e75caab382672abb4551a077cc93a2f49f2021 100644
--- a/src/redux/overlays/overlays.reducers.ts
+++ b/src/redux/overlays/overlays.reducers.ts
@@ -1,5 +1,11 @@
 import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
-import { addOverlay, getAllPublicOverlaysByProjectId } from './overlays.thunks';
+import {
+  addOverlay,
+  getAllPublicOverlaysByProjectId,
+  getAllUserOverlaysByCreator,
+  removeOverlay,
+  updateOverlays,
+} from './overlays.thunks';
 import { OverlaysState } from './overlays.types';
 
 export const getAllPublicOverlaysByProjectIdReducer = (
@@ -30,3 +36,45 @@ export const addOverlayReducer = (builder: ActionReducerMapBuilder<OverlaysState
     // TODO to discuss manage state of failure
   });
 };
+
+export const getAllUserOverlaysByCreatorReducer = (
+  builder: ActionReducerMapBuilder<OverlaysState>,
+): void => {
+  builder.addCase(getAllUserOverlaysByCreator.pending, state => {
+    state.userOverlays.loading = 'pending';
+  });
+  builder.addCase(getAllUserOverlaysByCreator.fulfilled, (state, action) => {
+    state.userOverlays.data = action.payload;
+    state.userOverlays.loading = 'succeeded';
+  });
+  builder.addCase(getAllUserOverlaysByCreator.rejected, state => {
+    state.userOverlays.loading = 'failed';
+    // TODO to discuss manage state of failure
+  });
+};
+
+export const updateOverlaysReducer = (builder: ActionReducerMapBuilder<OverlaysState>): void => {
+  builder.addCase(updateOverlays.pending, state => {
+    state.updateOverlays.loading = 'pending';
+  });
+  builder.addCase(updateOverlays.fulfilled, state => {
+    state.updateOverlays.loading = 'succeeded';
+  });
+  builder.addCase(updateOverlays.rejected, state => {
+    state.updateOverlays.loading = 'failed';
+    // TODO to discuss manage state of failure
+  });
+};
+
+export const removeOverlayReducer = (builder: ActionReducerMapBuilder<OverlaysState>): void => {
+  builder.addCase(removeOverlay.pending, state => {
+    state.removeOverlay.loading = 'pending';
+  });
+  builder.addCase(removeOverlay.fulfilled, state => {
+    state.removeOverlay.loading = 'succeeded';
+  });
+  builder.addCase(removeOverlay.rejected, state => {
+    state.removeOverlay.loading = 'failed';
+    // TODO to discuss manage state of failure
+  });
+};
diff --git a/src/redux/overlays/overlays.selectors.ts b/src/redux/overlays/overlays.selectors.ts
index 03ee76e6f318c3e65bba58f0b8902e972eda95a8..38ba856745080b3c00303ddb5d85eb881c1de478 100644
--- a/src/redux/overlays/overlays.selectors.ts
+++ b/src/redux/overlays/overlays.selectors.ts
@@ -16,3 +16,15 @@ export const loadingAddOverlay = createSelector(
   overlaysSelector,
   state => state.addOverlay.loading,
 );
+
+const userOverlaysSelector = createSelector(overlaysSelector, overlays => overlays.userOverlays);
+
+export const loadingUserOverlaysSelector = createSelector(
+  userOverlaysSelector,
+  state => state.loading,
+);
+
+export const userOverlaysDataSelector = createSelector(
+  userOverlaysSelector,
+  overlays => overlays.data,
+);
diff --git a/src/redux/overlays/overlays.slice.ts b/src/redux/overlays/overlays.slice.ts
index 5f49156af3e1b54b2074c7ae9b653e80f7488027..edb5f38140a3522677e9e818f0e545411365450a 100644
--- a/src/redux/overlays/overlays.slice.ts
+++ b/src/redux/overlays/overlays.slice.ts
@@ -1,5 +1,11 @@
 import { createSlice } from '@reduxjs/toolkit';
-import { addOverlayReducer, getAllPublicOverlaysByProjectIdReducer } from './overlays.reducers';
+import {
+  addOverlayReducer,
+  getAllPublicOverlaysByProjectIdReducer,
+  getAllUserOverlaysByCreatorReducer,
+  removeOverlayReducer,
+  updateOverlaysReducer,
+} from './overlays.reducers';
 import { OverlaysState } from './overlays.types';
 
 const initialState: OverlaysState = {
@@ -10,6 +16,19 @@ const initialState: OverlaysState = {
     loading: 'idle',
     error: { name: '', message: '' },
   },
+  userOverlays: {
+    data: [],
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
+  updateOverlays: {
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
+  removeOverlay: {
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
 };
 
 const overlaysState = createSlice({
@@ -19,6 +38,9 @@ const overlaysState = createSlice({
   extraReducers: builder => {
     getAllPublicOverlaysByProjectIdReducer(builder);
     addOverlayReducer(builder);
+    getAllUserOverlaysByCreatorReducer(builder);
+    updateOverlaysReducer(builder);
+    removeOverlayReducer(builder);
   },
 });
 
diff --git a/src/redux/overlays/overlays.thunks.ts b/src/redux/overlays/overlays.thunks.ts
index 330e5ee98aba5a26299f21b8d56c9b29e16d2d1e..5335fa4d505dab679eab4e86262746569708c582 100644
--- a/src/redux/overlays/overlays.thunks.ts
+++ b/src/redux/overlays/overlays.thunks.ts
@@ -12,6 +12,7 @@ import { createAsyncThunk } from '@reduxjs/toolkit';
 import { z } from 'zod';
 import { apiPath } from '../apiPath';
 import { CHUNK_SIZE } from './overlays.constants';
+import { closeModal } from '../modal/modal.slice';
 
 export const getAllPublicOverlaysByProjectId = createAsyncThunk(
   'overlays/getAllPublicOverlaysByProjectId',
@@ -158,3 +159,66 @@ export const addOverlay = createAsyncThunk(
     });
   },
 );
+
+export const getAllUserOverlaysByCreator = createAsyncThunk(
+  'overlays/getAllUserOverlaysByCreator',
+  async (creator: string): Promise<MapOverlay[]> => {
+    const response = await axiosInstance(
+      apiPath.getAllUserOverlaysByCreatorQuery({
+        creator,
+        publicOverlay: false,
+      }),
+      {
+        withCredentials: true,
+      },
+    );
+
+    const isDataValid = validateDataUsingZodSchema(response.data, z.array(mapOverlay));
+
+    const sortByOrder = (userOverlayA: MapOverlay, userOverlayB: MapOverlay): number => {
+      if (userOverlayA.order > userOverlayB.order) return 1;
+      return -1;
+    };
+
+    const sortedUserOverlays = response.data.sort(sortByOrder);
+
+    return isDataValid ? sortedUserOverlays : [];
+  },
+);
+
+export const updateOverlays = createAsyncThunk(
+  'overlays/updateOverlays',
+  async (userOverlays: MapOverlay[]): Promise<void> => {
+    const userOverlaysPromises = userOverlays.map(userOverlay =>
+      axiosInstance.patch<MapOverlay>(
+        apiPath.updateOverlay(userOverlay.idObject),
+        {
+          overlay: userOverlay,
+        },
+        {
+          withCredentials: true,
+        },
+      ),
+    );
+
+    const userOverlaysResponses = await Promise.all(userOverlaysPromises);
+
+    const updatedUserOverlays = userOverlaysResponses.map(
+      updatedUserOverlay => updatedUserOverlay.data,
+    );
+
+    validateDataUsingZodSchema(updatedUserOverlays, z.array(mapOverlay));
+  },
+);
+
+export const removeOverlay = createAsyncThunk(
+  'overlays/removeOverlay',
+  async ({ overlayId, login }: { overlayId: number; login: string }, thunkApi): Promise<void> => {
+    await axiosInstance.delete(apiPath.removeOverlay(overlayId), {
+      withCredentials: true,
+    });
+
+    await thunkApi.dispatch(getAllUserOverlaysByCreator(login));
+    thunkApi.dispatch(closeModal());
+  },
+);
diff --git a/src/redux/overlays/overlays.types.ts b/src/redux/overlays/overlays.types.ts
index 15d4d813a5879a8e5986e1daf411eceda9f5ef55..98aabe67dc58dad408fe904006907b8eddcd7eb1 100644
--- a/src/redux/overlays/overlays.types.ts
+++ b/src/redux/overlays/overlays.types.ts
@@ -9,4 +9,26 @@ export type AddOverlayState = {
   };
 };
 
-export type OverlaysState = FetchDataState<MapOverlay[] | []> & AddOverlayState;
+export type UpdateOverlaysState = {
+  updateOverlays: {
+    loading: Loading;
+    error: Error;
+  };
+};
+
+export type RemoveOverlayState = {
+  removeOverlay: {
+    loading: Loading;
+    error: Error;
+  };
+};
+
+export type UserOverlays = {
+  userOverlays: FetchDataState<MapOverlay[] | []>;
+};
+
+export type OverlaysState = FetchDataState<MapOverlay[] | []> &
+  AddOverlayState &
+  UserOverlays &
+  UpdateOverlaysState &
+  RemoveOverlayState;
diff --git a/src/redux/plugins/plugins.constants.ts b/src/redux/plugins/plugins.constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c3365278b4f0cfc8eaedb8832ad14afbf2d3cad9
--- /dev/null
+++ b/src/redux/plugins/plugins.constants.ts
@@ -0,0 +1,13 @@
+import { PluginsState } from './plugins.types';
+
+export const PLUGINS_INITIAL_STATE: PluginsState = {
+  list: {
+    data: [],
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
+  activePlugins: {
+    data: {},
+    pluginsId: [],
+  },
+};
diff --git a/src/redux/plugins/plugins.mock.ts b/src/redux/plugins/plugins.mock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9b6b9c8f12621dfa722ed20e45d6aec0c69408ba
--- /dev/null
+++ b/src/redux/plugins/plugins.mock.ts
@@ -0,0 +1,18 @@
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { ActivePlugins, PluginsList, PluginsState } from './plugins.types';
+
+export const PLUGINS_INITIAL_STATE_ACTIVE_PLUGINS_MOCK: ActivePlugins = {
+  data: {},
+  pluginsId: [],
+};
+
+export const PLUGINS_INITIAL_STATE_LIST_MOCK: PluginsList = {
+  data: [],
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
+
+export const PLUGINS_INITIAL_STATE_MOCK: PluginsState = {
+  list: PLUGINS_INITIAL_STATE_LIST_MOCK,
+  activePlugins: PLUGINS_INITIAL_STATE_ACTIVE_PLUGINS_MOCK,
+};
diff --git a/src/redux/plugins/plugins.reducers.test.ts b/src/redux/plugins/plugins.reducers.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..edc59097d4d53fe239bace4d11948391b3857847
--- /dev/null
+++ b/src/redux/plugins/plugins.reducers.test.ts
@@ -0,0 +1,98 @@
+/* eslint-disable no-magic-numbers */
+import {
+  ToolkitStoreWithSingleSlice,
+  createStoreInstanceUsingSliceReducer,
+} from '@/utils/createStoreInstanceUsingSliceReducer';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { HttpStatusCode } from 'axios';
+import { pluginFixture } from '@/models/fixtures/pluginFixture';
+import { apiPath } from '../apiPath';
+import { PluginsState } from './plugins.types';
+import pluginsReducer, { removePlugin } from './plugins.slice';
+import { registerPlugin } from './plugins.thunks';
+import { PLUGINS_INITIAL_STATE_MOCK } from './plugins.mock';
+
+const mockedAxiosClient = mockNetworkResponse();
+
+describe('plugins reducer', () => {
+  let store = {} as ToolkitStoreWithSingleSlice<PluginsState>;
+  beforeEach(() => {
+    store = createStoreInstanceUsingSliceReducer('plugins', pluginsReducer);
+  });
+
+  it('should match initial state', () => {
+    const action = { type: 'unknown' };
+
+    expect(pluginsReducer(undefined, action)).toEqual(PLUGINS_INITIAL_STATE_MOCK);
+  });
+  it('should remove overlay from store properly', () => {
+    const { type, payload } = store.dispatch(
+      removePlugin({
+        pluginId: 'hash1',
+      }),
+    );
+
+    expect(type).toBe('plugins/removePlugin');
+    expect(payload).toEqual({ pluginId: 'hash1' });
+  });
+  it('should update store after successful registerPlugin query', async () => {
+    mockedAxiosClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.Ok, pluginFixture);
+
+    const { type } = await store.dispatch(
+      registerPlugin({
+        hash: pluginFixture.hash,
+        isPublic: pluginFixture.isPublic,
+        pluginName: pluginFixture.name,
+        pluginUrl: pluginFixture.urls[0],
+        pluginVersion: pluginFixture.version,
+      }),
+    );
+
+    expect(type).toBe('plugins/registerPlugin/fulfilled');
+    const { data, pluginsId } = store.getState().plugins.activePlugins;
+
+    expect(data[pluginFixture.hash]).toEqual(pluginFixture);
+    expect(pluginsId).toContain(pluginFixture.hash);
+  });
+
+  it('should update store after failed registerPlugin query', async () => {
+    mockedAxiosClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.NotFound, undefined);
+
+    const { type, payload } = await store.dispatch(
+      registerPlugin({
+        hash: pluginFixture.hash,
+        isPublic: pluginFixture.isPublic,
+        pluginName: pluginFixture.name,
+        pluginUrl: pluginFixture.urls[0],
+        pluginVersion: pluginFixture.version,
+      }),
+    );
+
+    expect(type).toBe('plugins/registerPlugin/rejected');
+    expect(payload).toEqual(undefined);
+    const { data, pluginsId } = store.getState().plugins.activePlugins;
+
+    expect(data).toEqual({});
+
+    expect(pluginsId).not.toContain(pluginFixture.hash);
+  });
+
+  it('should update store on loading registerPlugin query', async () => {
+    mockedAxiosClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.NotFound, undefined);
+
+    store.dispatch(
+      registerPlugin({
+        hash: pluginFixture.hash,
+        isPublic: pluginFixture.isPublic,
+        pluginName: pluginFixture.name,
+        pluginUrl: pluginFixture.urls[0],
+        pluginVersion: pluginFixture.version,
+      }),
+    );
+
+    const { data, pluginsId } = store.getState().plugins.activePlugins;
+
+    expect(data).toEqual({});
+    expect(pluginsId).toContain(pluginFixture.hash);
+  });
+});
diff --git a/src/redux/plugins/plugins.reducers.ts b/src/redux/plugins/plugins.reducers.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f046459c4c9e88879b6d7b9ee88a755e7e29ddc1
--- /dev/null
+++ b/src/redux/plugins/plugins.reducers.ts
@@ -0,0 +1,40 @@
+import type { ActionReducerMapBuilder } from '@reduxjs/toolkit';
+import type { PluginsState, RemovePluginAction } from './plugins.types';
+import { registerPlugin, getAllPlugins } from './plugins.thunks';
+
+export const removePluginReducer = (state: PluginsState, action: RemovePluginAction): void => {
+  const { pluginId } = action.payload;
+  state.activePlugins.pluginsId = state.activePlugins.pluginsId.filter(id => id !== pluginId);
+  delete state.activePlugins.data[pluginId];
+};
+
+export const registerPluginReducer = (builder: ActionReducerMapBuilder<PluginsState>): void => {
+  builder.addCase(registerPlugin.pending, (state, action) => {
+    const { hash } = action.meta.arg;
+    state.activePlugins.pluginsId.push(hash);
+  });
+  builder.addCase(registerPlugin.fulfilled, (state, action) => {
+    if (action.payload) {
+      const { hash } = action.meta.arg;
+
+      state.activePlugins.data[hash] = action.payload;
+    }
+  });
+  builder.addCase(registerPlugin.rejected, state => {
+    state.activePlugins.pluginsId = [];
+  });
+};
+
+export const getAllPluginsReducer = (builder: ActionReducerMapBuilder<PluginsState>): void => {
+  builder.addCase(getAllPlugins.pending, state => {
+    state.list.loading = 'pending';
+  });
+  builder.addCase(getAllPlugins.fulfilled, (state, action) => {
+    state.list.data = action.payload || [];
+    state.list.loading = 'succeeded';
+  });
+  builder.addCase(getAllPlugins.rejected, state => {
+    state.list.loading = 'failed';
+    // TODO to discuss manage state of failure
+  });
+};
diff --git a/src/redux/plugins/plugins.selectors.ts b/src/redux/plugins/plugins.selectors.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1bf37c638ee768446fe26c5229f4e4a51e134f14
--- /dev/null
+++ b/src/redux/plugins/plugins.selectors.ts
@@ -0,0 +1,67 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { MinervaPlugin } from '@/types/models';
+import { rootSelector } from '../root/root.selectors';
+
+export const pluginsSelector = createSelector(rootSelector, state => state.plugins);
+
+export const pluginsListSelector = createSelector(pluginsSelector, plugins => {
+  return plugins.list;
+});
+
+export const pluginsListDataSelector = createSelector(pluginsListSelector, pluginsList => {
+  return pluginsList.data;
+});
+
+export const publicPluginsListSelector = createSelector(
+  pluginsListDataSelector,
+  pluginsListData => {
+    return (pluginsListData || []).filter(plugin => plugin.isPublic);
+  },
+);
+
+export const activePluginsSelector = createSelector(pluginsSelector, state => state.activePlugins);
+
+export const activePluginsIdSelector = createSelector(
+  activePluginsSelector,
+  state => state.pluginsId,
+);
+
+export const activePluginsDataSelector = createSelector(
+  activePluginsSelector,
+  plugins => plugins.data,
+);
+
+export const allActivePluginsSelector = createSelector(
+  activePluginsDataSelector,
+  activePluginsIdSelector,
+  (data, pluginsId) => {
+    const result: MinervaPlugin[] = [];
+
+    pluginsId.forEach(pluginId => {
+      const element = data[pluginId];
+      if (element) {
+        result.push(element);
+      }
+    });
+
+    return result;
+  },
+);
+
+export const privateActivePluginsSelector = createSelector(
+  allActivePluginsSelector,
+  activePlugins => {
+    return (activePlugins || []).filter(plugin => !plugin.isPublic);
+  },
+);
+
+export const isPluginActiveSelector = createSelector(
+  [activePluginsIdSelector, (_, activePlugin: string): string => activePlugin],
+  (activePlugins, activePlugin) => activePlugins.includes(activePlugin),
+);
+
+export const isPluginLoadingSelector = createSelector(
+  [activePluginsSelector, (_, activePlugins: string): string => activePlugins],
+  ({ data, pluginsId }, pluginId) =>
+    pluginsId.includes(pluginId) && data[pluginId] && !Object.keys(data[pluginId]).length,
+);
diff --git a/src/redux/plugins/plugins.slice.ts b/src/redux/plugins/plugins.slice.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aeb408420001e991c41e1a060c280880450af4af
--- /dev/null
+++ b/src/redux/plugins/plugins.slice.ts
@@ -0,0 +1,23 @@
+import { createSlice } from '@reduxjs/toolkit';
+import {
+  registerPluginReducer,
+  removePluginReducer,
+  getAllPluginsReducer,
+} from './plugins.reducers';
+
+import { PLUGINS_INITIAL_STATE } from './plugins.constants';
+
+const pluginsSlice = createSlice({
+  name: 'plugins',
+  initialState: PLUGINS_INITIAL_STATE,
+  reducers: {
+    removePlugin: removePluginReducer,
+  },
+  extraReducers: builder => {
+    registerPluginReducer(builder);
+    getAllPluginsReducer(builder);
+  },
+});
+
+export const { removePlugin } = pluginsSlice.actions;
+export default pluginsSlice.reducer;
diff --git a/src/redux/plugins/plugins.thunks.test.ts b/src/redux/plugins/plugins.thunks.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7972222c206923167271607d9c4e844b56d55556
--- /dev/null
+++ b/src/redux/plugins/plugins.thunks.test.ts
@@ -0,0 +1,63 @@
+/* eslint-disable no-magic-numbers */
+import axios, { HttpStatusCode } from 'axios';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import MockAdapter from 'axios-mock-adapter';
+import { pluginFixture } from '@/models/fixtures/pluginFixture';
+import {
+  ToolkitStoreWithSingleSlice,
+  createStoreInstanceUsingSliceReducer,
+} from '@/utils/createStoreInstanceUsingSliceReducer';
+import { apiPath } from '../apiPath';
+import { PluginsState } from './plugins.types';
+import pluginsReducer from './plugins.slice';
+import { getInitPlugins } from './plugins.thunks';
+
+const mockedAxiosApiClient = mockNetworkResponse();
+const mockedAxiosClient = new MockAdapter(axios);
+
+describe('plugins - thunks', () => {
+  describe('getInitPlugins', () => {
+    let store = {} as ToolkitStoreWithSingleSlice<PluginsState>;
+    beforeEach(() => {
+      store = createStoreInstanceUsingSliceReducer('plugins', pluginsReducer);
+    });
+    const setHashedPluginMock = jest.fn();
+
+    beforeEach(() => {
+      setHashedPluginMock.mockClear();
+    });
+
+    it('should fetch and load initial plugins', async () => {
+      mockedAxiosApiClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.Ok, pluginFixture);
+      mockedAxiosApiClient
+        .onGet(apiPath.getPlugin(pluginFixture.hash))
+        .reply(HttpStatusCode.Ok, pluginFixture);
+      mockedAxiosClient.onGet(pluginFixture.urls[0]).reply(HttpStatusCode.Ok, '');
+
+      await store.dispatch(
+        getInitPlugins({
+          pluginsId: [pluginFixture.hash],
+          setHashedPlugin: setHashedPluginMock,
+        }),
+      );
+
+      expect(setHashedPluginMock).toHaveBeenCalledTimes(1);
+    });
+    it('should not load plugin if fetched plugin is not valid', async () => {
+      mockedAxiosApiClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.NotFound, {});
+      mockedAxiosApiClient
+        .onGet(apiPath.getPlugin(pluginFixture.hash))
+        .reply(HttpStatusCode.NotFound, {});
+      mockedAxiosClient.onGet(pluginFixture.urls[0]).reply(HttpStatusCode.NotFound, '');
+
+      await store.dispatch(
+        getInitPlugins({
+          pluginsId: [pluginFixture.hash],
+          setHashedPlugin: setHashedPluginMock,
+        }),
+      );
+
+      expect(setHashedPluginMock).not.toHaveBeenCalled();
+    });
+  });
+});
diff --git a/src/redux/plugins/plugins.thunks.ts b/src/redux/plugins/plugins.thunks.ts
new file mode 100644
index 0000000000000000000000000000000000000000..73c7341e07cfc2f9b93515487084fe26fade667d
--- /dev/null
+++ b/src/redux/plugins/plugins.thunks.ts
@@ -0,0 +1,97 @@
+/* eslint-disable no-magic-numbers */
+import axios from 'axios';
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+import { pluginSchema } from '@/models/pluginSchema';
+import type { MinervaPlugin } from '@/types/models';
+import { axiosInstance } from '@/services/api/utils/axiosInstance';
+import { z } from 'zod';
+import { apiPath } from '../apiPath';
+
+type RegisterPlugin = {
+  hash: string;
+  pluginUrl: string;
+  pluginName: string;
+  pluginVersion: string;
+  isPublic: boolean;
+};
+
+export const registerPlugin = createAsyncThunk(
+  'plugins/registerPlugin',
+  async ({
+    hash,
+    isPublic,
+    pluginName,
+    pluginUrl,
+    pluginVersion,
+  }: RegisterPlugin): Promise<MinervaPlugin | undefined> => {
+    const payload = {
+      hash,
+      url: pluginUrl,
+      name: pluginName,
+      version: pluginVersion,
+      isPublic: isPublic.toString(),
+    } as const;
+
+    const response = await axiosInstance.post<MinervaPlugin>(
+      apiPath.registerPluign(),
+      new URLSearchParams(payload),
+      {
+        withCredentials: true,
+      },
+    );
+
+    const isDataValid = validateDataUsingZodSchema(response.data, pluginSchema);
+
+    if (isDataValid) {
+      return response.data;
+    }
+
+    return undefined;
+  },
+);
+
+type GetInitPluginsProps = {
+  pluginsId: string[];
+  setHashedPlugin: ({
+    pluginUrl,
+    pluginScript,
+  }: {
+    pluginUrl: string;
+    pluginScript: string;
+  }) => void;
+};
+
+export const getInitPlugins = createAsyncThunk<void, GetInitPluginsProps>(
+  'plugins/getInitPlugins',
+  async ({ pluginsId, setHashedPlugin }): Promise<void> => {
+    /* eslint-disable no-restricted-syntax, no-await-in-loop */
+    for (const pluginId of pluginsId) {
+      const res = await axiosInstance<MinervaPlugin>(apiPath.getPlugin(pluginId));
+
+      const isDataValid = validateDataUsingZodSchema(res.data, pluginSchema);
+
+      if (isDataValid) {
+        const { urls } = res.data;
+        const scriptRes = await axios(urls[0]);
+        const pluginScript = scriptRes.data;
+        setHashedPlugin({ pluginUrl: urls[0], pluginScript });
+
+        /* eslint-disable no-new-func */
+        const loadPlugin = new Function(pluginScript);
+        loadPlugin();
+      }
+    }
+  },
+);
+
+export const getAllPlugins = createAsyncThunk(
+  'plugins/getAllPlugins',
+  async (): Promise<MinervaPlugin[]> => {
+    const response = await axiosInstance.get<MinervaPlugin[]>(apiPath.getAllPlugins());
+
+    const isDataValid = validateDataUsingZodSchema(response.data, z.array(pluginSchema));
+
+    return isDataValid ? response.data : [];
+  },
+);
diff --git a/src/redux/plugins/plugins.types.ts b/src/redux/plugins/plugins.types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2569f12845cc3394a7b8897e9133745a52cb9fa6
--- /dev/null
+++ b/src/redux/plugins/plugins.types.ts
@@ -0,0 +1,20 @@
+import { PayloadAction } from '@reduxjs/toolkit';
+
+import { FetchDataState } from '@/types/fetchDataState';
+import { MinervaPlugin } from '@/types/models';
+
+export type RemovePluginPayload = { pluginId: string };
+export type RemovePluginAction = PayloadAction<RemovePluginPayload>;
+
+export type PluginsList = FetchDataState<MinervaPlugin[]>;
+export type ActivePlugins = {
+  pluginsId: string[];
+  data: {
+    [pluginId: string]: MinervaPlugin;
+  };
+};
+
+export type PluginsState = {
+  list: PluginsList;
+  activePlugins: ActivePlugins;
+};
diff --git a/src/redux/root/init.thunks.ts b/src/redux/root/init.thunks.ts
index c4ac19274381cdffa49913eff2a4e40ed79960e7..557e87d96f6804aed9e108a81d9530a2cd93ccf2 100644
--- a/src/redux/root/init.thunks.ts
+++ b/src/redux/root/init.thunks.ts
@@ -1,25 +1,27 @@
-import { openSearchDrawerWithSelectedTab } from '@/redux/drawer/drawer.slice';
-import { createAsyncThunk } from '@reduxjs/toolkit';
 import { PROJECT_ID } from '@/constants';
+import { openSearchDrawerWithSelectedTab } from '@/redux/drawer/drawer.slice';
 import { AppDispatch } from '@/redux/store';
 import { QueryData } from '@/types/query';
 import { getDefaultSearchTab } from '@/components/FunctionalArea/TopBar/SearchBar/SearchBar.utils';
+import { PluginsManager } from '@/services/pluginsManager';
+import { createAsyncThunk } from '@reduxjs/toolkit';
 import { getAllBackgroundsByProjectId } from '../backgrounds/backgrounds.thunks';
-import { getAllPublicOverlaysByProjectId } from '../overlays/overlays.thunks';
-import { getModels } from '../models/models.thunks';
-import { getProjectById } from '../project/project.thunks';
+import { getConfiguration, getConfigurationOptions } from '../configuration/configuration.thunks';
 import {
   initMapBackground,
   initMapPosition,
   initMapSizeAndModelId,
   initOpenedMaps,
 } from '../map/map.thunks';
-import { getSearchData } from '../search/search.thunks';
-import { setPerfectMatch } from '../search/search.slice';
-import { getSessionValid } from '../user/user.thunks';
+import { getModels } from '../models/models.thunks';
 import { getInitOverlays } from '../overlayBioEntity/overlayBioEntity.thunk';
-import { getConfiguration, getConfigurationOptions } from '../configuration/configuration.thunks';
+import { getAllPublicOverlaysByProjectId } from '../overlays/overlays.thunks';
+import { getAllPlugins, getInitPlugins } from '../plugins/plugins.thunks';
+import { getProjectById } from '../project/project.thunks';
+import { setPerfectMatch } from '../search/search.slice';
+import { getSearchData } from '../search/search.thunks';
 import { getStatisticsById } from '../statistics/statistics.thunks';
+import { getSessionValid } from '../user/user.thunks';
 
 interface InitializeAppParams {
   queryData: QueryData;
@@ -31,6 +33,7 @@ export const fetchInitialAppData = createAsyncThunk<
   { dispatch: AppDispatch }
 >('appInit/fetchInitialAppData', async ({ queryData }, { dispatch }): Promise<void> => {
   /** Fetch all data required for rendering map */
+
   await Promise.all([
     dispatch(getConfigurationOptions()),
     dispatch(getProjectById(PROJECT_ID)),
@@ -54,6 +57,9 @@ export const fetchInitialAppData = createAsyncThunk<
   dispatch(getStatisticsById(PROJECT_ID));
   dispatch(getConfiguration());
 
+  // Fetch plugins list
+  dispatch(getAllPlugins());
+
   /** Trigger search */
   if (queryData.searchValue) {
     dispatch(setPerfectMatch(queryData.perfectMatch));
@@ -70,4 +76,13 @@ export const fetchInitialAppData = createAsyncThunk<
   if (queryData.overlaysId) {
     dispatch(getInitOverlays({ overlaysId: queryData.overlaysId }));
   }
+
+  if (queryData.pluginsId) {
+    dispatch(
+      getInitPlugins({
+        pluginsId: queryData.pluginsId,
+        setHashedPlugin: PluginsManager.setHashedPlugin,
+      }),
+    );
+  }
 });
diff --git a/src/redux/root/query.selectors.ts b/src/redux/root/query.selectors.ts
index 3088b0dacb0ae0051fb11a60a658af927aff4667..b862ed429fdb885367f3f87755c47204903b08b7 100644
--- a/src/redux/root/query.selectors.ts
+++ b/src/redux/root/query.selectors.ts
@@ -4,22 +4,26 @@ import { ZERO } from '@/constants/common';
 import { mapDataSelector } from '../map/map.selectors';
 import { perfectMatchSelector, searchValueSelector } from '../search/search.selectors';
 import { activeOverlaysIdSelector } from '../overlayBioEntity/overlayBioEntity.selector';
+import { activePluginsIdSelector } from '../plugins/plugins.selectors';
 
 export const queryDataParamsSelector = createSelector(
   searchValueSelector,
   perfectMatchSelector,
   mapDataSelector,
   activeOverlaysIdSelector,
+  activePluginsIdSelector,
   (
     searchValue,
     perfectMatch,
     { modelId, backgroundId, position },
     activeOverlaysId,
+    activePluginsId,
   ): QueryDataParams => {
     const joinedSearchValue = searchValue.join(';');
     const shouldIncludeSearchValue = searchValue.length > ZERO && joinedSearchValue;
 
     const shouldIncludeOverlaysId = activeOverlaysId.length > ZERO;
+    const shouldIncludePluginsId = activePluginsId.length > ZERO;
 
     const queryDataParams: QueryDataParams = {
       perfectMatch,
@@ -28,6 +32,7 @@ export const queryDataParamsSelector = createSelector(
       ...position.last,
       ...(shouldIncludeSearchValue ? { searchValue: joinedSearchValue } : {}),
       ...(shouldIncludeOverlaysId ? { overlaysId: activeOverlaysId.join(',') } : {}),
+      ...(shouldIncludePluginsId ? { pluginsId: activePluginsId.join(',') } : {}),
     };
 
     return queryDataParams;
diff --git a/src/redux/root/root.fixtures.ts b/src/redux/root/root.fixtures.ts
index 77d70737a030314a15c3b1322df0b1782ea365c9..b27b88cc9c1c96511ed626d5568b30d04999b1d3 100644
--- a/src/redux/root/root.fixtures.ts
+++ b/src/redux/root/root.fixtures.ts
@@ -6,12 +6,14 @@ import { CONTEXT_MENU_INITIAL_STATE } from '../contextMenu/contextMenu.constants
 import { COOKIE_BANNER_INITIAL_STATE_MOCK } from '../cookieBanner/cookieBanner.mock';
 import { initialStateFixture as drawerInitialStateMock } from '../drawer/drawerFixture';
 import { DRUGS_INITIAL_STATE_MOCK } from '../drugs/drugs.mock';
+import { EXPORT_INITIAL_STATE_MOCK } from '../export/export.mock';
 import { LEGEND_INITIAL_STATE_MOCK } from '../legend/legend.mock';
 import { initialMapStateFixture } from '../map/map.fixtures';
 import { MODAL_INITIAL_STATE_MOCK } from '../modal/modal.mock';
 import { MODELS_INITIAL_STATE_MOCK } from '../models/models.mock';
 import { OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK } from '../overlayBioEntity/overlayBioEntity.mock';
 import { OVERLAYS_INITIAL_STATE_MOCK } from '../overlays/overlays.mock';
+import { PLUGINS_INITIAL_STATE_MOCK } from '../plugins/plugins.mock';
 import { PROJECT_STATE_INITIAL_MOCK } from '../project/project.mock';
 import { REACTIONS_STATE_INITIAL_MOCK } from '../reactions/reactions.mock';
 import { SEARCH_STATE_INITIAL_MOCK } from '../search/search.mock';
@@ -43,4 +45,6 @@ export const INITIAL_STORE_STATE_MOCK: RootState = {
   statistics: STATISTICS_STATE_INITIAL_MOCK,
   compartmentPathways: COMPARTMENT_PATHWAYS_INITIAL_STATE_MOCK,
   publications: PUBLICATIONS_INITIAL_STATE_MOCK,
+  export: EXPORT_INITIAL_STATE_MOCK,
+  plugins: PLUGINS_INITIAL_STATE_MOCK,
 };
diff --git a/src/redux/statistics/statistics.selectors.ts b/src/redux/statistics/statistics.selectors.ts
index e0bb325940adba73600a3378ffff6d5ae979df8b..847e042f7d22fff19581cff553e59faf396a54fc 100644
--- a/src/redux/statistics/statistics.selectors.ts
+++ b/src/redux/statistics/statistics.selectors.ts
@@ -9,8 +9,3 @@ export const statisticsDataSelector = createSelector(
   statisticsSelector,
   statistics => statistics?.data,
 );
-
-export const elementAnnotationsSelector = createSelector(
-  statisticsDataSelector,
-  statistics => statistics?.elementAnnotations,
-);
diff --git a/src/redux/store.ts b/src/redux/store.ts
index 32c4c738048dc5fd63bda60d4391003dc701f1fb..925fb4094256ffe3ccd792ba655e0d24e717e919 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -22,10 +22,12 @@ import {
   TypedStartListening,
   configureStore,
 } from '@reduxjs/toolkit';
+import compartmentPathwaysReducer from './compartmentPathways/compartmentPathways.slice';
+import exportReducer from './export/export.slice';
 import legendReducer from './legend/legend.slice';
 import { mapListenerMiddleware } from './map/middleware/map.middleware';
+import pluginsReducer from './plugins/plugins.slice';
 import statisticsReducer from './statistics/statistics.slice';
-import compartmentPathwaysReducer from './compartmentPathways/compartmentPathways.slice';
 import publicationsReducer from './publications/publications.slice';
 
 export const reducers = {
@@ -50,6 +52,8 @@ export const reducers = {
   statistics: statisticsReducer,
   compartmentPathways: compartmentPathwaysReducer,
   publications: publicationsReducer,
+  export: exportReducer,
+  plugins: pluginsReducer,
 };
 
 export const middlewares = [mapListenerMiddleware.middleware];
diff --git a/src/redux/user/user.reducers.ts b/src/redux/user/user.reducers.ts
index 56c847b9497038441472a5afc8bbb7ae5f488bf0..83618692cf8f791128420d955c3f4ae4068dac5c 100644
--- a/src/redux/user/user.reducers.ts
+++ b/src/redux/user/user.reducers.ts
@@ -7,9 +7,10 @@ export const loginReducer = (builder: ActionReducerMapBuilder<UserState>): void
     .addCase(login.pending, state => {
       state.loading = 'pending';
     })
-    .addCase(login.fulfilled, state => {
+    .addCase(login.fulfilled, (state, action) => {
       state.authenticated = true;
       state.loading = 'succeeded';
+      state.login = action.payload?.login || null;
     })
     .addCase(login.rejected, state => {
       state.authenticated = false;
diff --git a/src/redux/user/user.selectors.ts b/src/redux/user/user.selectors.ts
index 5331af9df0173163e2383de42e0a2800a9414b15..026e5631ad9edff0fa196cc011273cf6fe410c45 100644
--- a/src/redux/user/user.selectors.ts
+++ b/src/redux/user/user.selectors.ts
@@ -5,3 +5,4 @@ export const userSelector = createSelector(rootSelector, state => state.user);
 
 export const authenticatedUserSelector = createSelector(userSelector, state => state.authenticated);
 export const loadingUserSelector = createSelector(userSelector, state => state.loading);
+export const loginUserSelector = createSelector(userSelector, state => state.login);
diff --git a/src/redux/user/user.thunks.ts b/src/redux/user/user.thunks.ts
index 3f4d97c26e526b7bdd779099340f5adae02231ea..95c567c2af83b31f62eb05c30d219f6f17bdb6af 100644
--- a/src/redux/user/user.thunks.ts
+++ b/src/redux/user/user.thunks.ts
@@ -3,6 +3,7 @@ import { createAsyncThunk } from '@reduxjs/toolkit';
 import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
 import { loginSchema } from '@/models/loginSchema';
 import { sessionSchemaValid } from '@/models/sessionValidSchema';
+import { Login, SessionValid } from '@/types/models';
 import { apiPath } from '../apiPath';
 import { closeModal } from '../modal/modal.slice';
 
@@ -10,7 +11,7 @@ export const login = createAsyncThunk(
   'user/login',
   async (credentials: { login: string; password: string }, { dispatch }) => {
     const searchParams = new URLSearchParams(credentials);
-    const response = await axiosInstance.post(apiPath.postLogin(), searchParams, {
+    const response = await axiosInstance.post<Login>(apiPath.postLogin(), searchParams, {
       withCredentials: true,
     });
 
@@ -22,11 +23,11 @@ export const login = createAsyncThunk(
 );
 
 export const getSessionValid = createAsyncThunk('user/getSessionValid', async () => {
-  const response = await axiosInstance.get(apiPath.getSessionValid(), {
+  const response = await axiosInstance.get<SessionValid>(apiPath.getSessionValid(), {
     withCredentials: true,
   });
 
   const isDataValid = validateDataUsingZodSchema(response.data, sessionSchemaValid);
 
-  return isDataValid ? response.data : undefined;
+  return isDataValid ? response.data.login : null;
 });
diff --git a/src/services/pluginsManager/index.ts b/src/services/pluginsManager/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c77cb1f59759be88679e29c12d76613f1f61be64
--- /dev/null
+++ b/src/services/pluginsManager/index.ts
@@ -0,0 +1 @@
+export { PluginsManager } from './pluginsManager';
diff --git a/src/services/pluginsManager/pluginsManager.test.ts b/src/services/pluginsManager/pluginsManager.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f9b55d2712e3cb23ec806e3440d373fd06bcd3d3
--- /dev/null
+++ b/src/services/pluginsManager/pluginsManager.test.ts
@@ -0,0 +1,75 @@
+/* eslint-disable no-magic-numbers */
+import { store } from '@/redux/store';
+import { configurationFixture } from '@/models/fixtures/configurationFixture';
+import { configurationMapper } from './pluginsManager.utils';
+import { PluginsManager } from './pluginsManager';
+
+jest.mock('../../redux/store');
+
+describe('PluginsManager', () => {
+  const originalWindow = { ...global.window };
+
+  beforeEach(() => {
+    global.window = { ...originalWindow };
+  });
+
+  afterEach(() => {
+    global.window = originalWindow;
+  });
+
+  afterEach(() => {
+    jest.clearAllMocks();
+  });
+
+  it('setHashedPlugin correctly computes hash and updates hashedPlugins', () => {
+    const pluginUrl = 'https://example.com/plugin.js';
+    const pluginScript = 'console.log("Hello, Plugin!");';
+
+    PluginsManager.setHashedPlugin({ pluginUrl, pluginScript });
+
+    expect(PluginsManager.hashedPlugins[pluginUrl]).toBe('edc7eeafccc9e1ab66f713298425947b');
+  });
+
+  it('init subscribes to store changes and updates minerva configuration', () => {
+    (store.getState as jest.Mock).mockReturnValueOnce({
+      configuration: { main: { data: configurationFixture } },
+    });
+
+    PluginsManager.init();
+
+    expect(store.subscribe).toHaveBeenCalled();
+
+    // Simulate store change
+    (store.subscribe as jest.Mock).mock.calls[0][0]();
+
+    expect(store.getState).toHaveBeenCalled();
+    expect(window.minerva.configuration).toEqual(configurationMapper(configurationFixture));
+  });
+  it('init does not update minerva configuration when configuration is undefined', () => {
+    (store.getState as jest.Mock).mockReturnValueOnce({
+      configuration: { main: { data: undefined } },
+    });
+
+    PluginsManager.init();
+
+    expect(store.subscribe).toHaveBeenCalled();
+
+    // Simulate store change
+    (store.subscribe as jest.Mock).mock.calls[0][0]();
+
+    expect(store.getState).toHaveBeenCalled();
+    expect(window.minerva.configuration).toBeUndefined();
+  });
+
+  it('registerPlugin dispatches action and returns element', () => {
+    const pluginName = 'TestPlugin';
+    const pluginVersion = '1.0.0';
+    const pluginUrl = 'https://example.com/test-plugin.js';
+
+    const result = PluginsManager.registerPlugin({ pluginName, pluginVersion, pluginUrl });
+
+    expect(store.dispatch).toHaveBeenCalled();
+
+    expect(result.element).toBeDefined();
+  });
+});
diff --git a/src/services/pluginsManager/pluginsManager.ts b/src/services/pluginsManager/pluginsManager.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a41a8ed5cad9d405bb07069425bf28f79b3112e5
--- /dev/null
+++ b/src/services/pluginsManager/pluginsManager.ts
@@ -0,0 +1,61 @@
+import md5 from 'crypto-js/md5';
+import { store } from '@/redux/store';
+import { registerPlugin } from '@/redux/plugins/plugins.thunks';
+import { configurationMapper } from './pluginsManager.utils';
+import type { PluginsManagerType } from './pluginsManager.types';
+
+export const PluginsManager: PluginsManagerType = {
+  hashedPlugins: {},
+  setHashedPlugin({ pluginUrl, pluginScript }) {
+    const hash = md5(pluginScript).toString();
+
+    PluginsManager.hashedPlugins[pluginUrl] = hash;
+
+    return hash;
+  },
+  init() {
+    window.minerva = {
+      plugins: {
+        registerPlugin: PluginsManager.registerPlugin,
+      },
+    };
+
+    const unsubscribe = store.subscribe(() => {
+      const configurationStore = store.getState().configuration.main.data;
+
+      if (configurationStore) {
+        const configuration = configurationMapper(configurationStore);
+
+        window.minerva = {
+          ...window.minerva,
+          configuration,
+        };
+      }
+    });
+
+    return unsubscribe;
+  },
+
+  registerPlugin({ pluginName, pluginVersion, pluginUrl }) {
+    const hash = PluginsManager.hashedPlugins[pluginUrl];
+
+    store.dispatch(
+      registerPlugin({
+        hash,
+        isPublic: false,
+        pluginName,
+        pluginUrl,
+        pluginVersion,
+      }),
+    );
+
+    // TODO: replace when plugins drawer is implemented
+    const element = document.createElement('div');
+    const wrapper = document.querySelector('#plugins');
+    wrapper?.append(element);
+
+    return {
+      element,
+    };
+  },
+};
diff --git a/src/services/pluginsManager/pluginsManager.types.ts b/src/services/pluginsManager/pluginsManager.types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cedb9034b59df6bb3726b1f57e1d3109814be189
--- /dev/null
+++ b/src/services/pluginsManager/pluginsManager.types.ts
@@ -0,0 +1,21 @@
+import { Unsubscribe } from '@reduxjs/toolkit';
+import { configurationMapper } from './pluginsManager.utils';
+
+export type RegisterPlugin = {
+  pluginName: string;
+  pluginVersion: string;
+  pluginUrl: string;
+};
+
+export type MinervaConfiguration = ReturnType<typeof configurationMapper>;
+
+export type PluginsManagerType = {
+  hashedPlugins: {
+    [url: string]: string;
+  };
+  setHashedPlugin({ pluginUrl, pluginScript }: { pluginUrl: string; pluginScript: string }): string;
+  init(): Unsubscribe;
+  registerPlugin({ pluginName, pluginVersion, pluginUrl }: RegisterPlugin): {
+    element: HTMLDivElement;
+  };
+};
diff --git a/src/services/pluginsManager/pluginsManager.utils.ts b/src/services/pluginsManager/pluginsManager.utils.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dd7158a5d30ae742bbde630778dbcbb66e94a072
--- /dev/null
+++ b/src/services/pluginsManager/pluginsManager.utils.ts
@@ -0,0 +1,14 @@
+import { Configuration } from '@/types/models';
+
+export const configurationMapper = (data: Configuration): unknown => ({
+  annotators: data.annotators,
+  elementTypes: data.elementTypes,
+  miramiTypes: data.miriamTypes,
+  mapTypes: data.mapTypes,
+  modelConverters: data.modelFormats,
+  modificationStateTypes: data.modificationStateTypes,
+  options: data.options,
+  overlayTypes: data.overlayTypes,
+  privilegeTypes: data.privilegeTypes,
+  reactionTypes: data.reactionTypes,
+});
diff --git a/src/shared/Icon/Icon.component.tsx b/src/shared/Icon/Icon.component.tsx
index 0dae32d43b3d4e3848f0dcbce4bbaebc30e6dab6..dd6d4decfbbe023e069d0ef06b80b088b2e3458d 100644
--- a/src/shared/Icon/Icon.component.tsx
+++ b/src/shared/Icon/Icon.component.tsx
@@ -18,6 +18,7 @@ import type { IconTypes } from '@/types/iconTypes';
 import { LocationIcon } from './Icons/LocationIcon';
 import { MaginfierZoomInIcon } from './Icons/MagnifierZoomIn';
 import { MaginfierZoomOutIcon } from './Icons/MagnifierZoomOut';
+import { ThreeDotsIcon } from './Icons/ThreeDotsIcon';
 
 export interface IconProps {
   className?: string;
@@ -43,6 +44,7 @@ const icons = {
   location: LocationIcon,
   'magnifier-zoom-in': MaginfierZoomInIcon,
   'magnifier-zoom-out': MaginfierZoomOutIcon,
+  'three-dots': ThreeDotsIcon,
 } as const;
 
 export const Icon = ({ name, className = '', ...rest }: IconProps): JSX.Element => {
diff --git a/src/shared/Icon/Icons/ThreeDotsIcon.tsx b/src/shared/Icon/Icons/ThreeDotsIcon.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..156e41e298f91f041e52b9573c2a3a85cf0e5735
--- /dev/null
+++ b/src/shared/Icon/Icons/ThreeDotsIcon.tsx
@@ -0,0 +1,27 @@
+interface ThreeDotsIconProps {
+  className?: string;
+}
+
+export const ThreeDotsIcon = ({ className }: ThreeDotsIconProps): JSX.Element => (
+  <svg
+    width="4"
+    height="22"
+    viewBox="0 0 4 22"
+    fill="none"
+    xmlns="http://www.w3.org/2000/svg"
+    className={className}
+  >
+    <path
+      d="M-8.74228e-08 11C-1.35705e-07 12.1046 0.89543 13 2 13C3.10457 13 4 12.1046 4 11C4 9.89543 3.10457 9 2 9C0.895431 9 -3.91405e-08 9.89543 -8.74228e-08 11Z"
+      fill="#070130"
+    />
+    <path
+      d="M-8.74228e-08 2C-1.35705e-07 3.10457 0.89543 4 2 4C3.10457 4 4 3.10457 4 2C4 0.89543 3.10457 -3.91405e-08 2 -8.74228e-08C0.895431 -1.35705e-07 -3.91405e-08 0.89543 -8.74228e-08 2Z"
+      fill="#070130"
+    />
+    <path
+      d="M-8.74228e-08 20C-1.35705e-07 21.1046 0.89543 22 2 22C3.10457 22 4 21.1046 4 20C4 18.8954 3.10457 18 2 18C0.895431 18 -3.91405e-08 18.8954 -8.74228e-08 20Z"
+      fill="#070130"
+    />
+  </svg>
+);
diff --git a/src/types/OLrendering.ts b/src/types/OLrendering.ts
index 11ab030c2ca0dd67874f94da6b29309e81f52e1c..6aee24d703ddc7ab5c39bf21644ad91895886891 100644
--- a/src/types/OLrendering.ts
+++ b/src/types/OLrendering.ts
@@ -1,5 +1,7 @@
 import { Color } from './models';
 
+export type OverlayBioEntityRenderType = 'line' | 'rectangle';
+
 export type OverlayBioEntityRender = {
   id: number;
   modelId: number;
@@ -16,4 +18,15 @@ export type OverlayBioEntityRender = {
   value: number | null;
   overlayId: number;
   color: Color | null;
+  type: OverlayBioEntityRenderType;
 };
+
+export interface OverlayReactionCoords {
+  x1: number;
+  x2: number;
+  y1: number;
+  y2: number;
+  id: number;
+  height: number;
+  width: number;
+}
diff --git a/src/types/drawerName.ts b/src/types/drawerName.ts
index a5f3e3d2ff2f0155c67bdb1a458fc2ce64c5764f..3715c57ddd45995b4c8194a917bf0ad8a129b5f4 100644
--- a/src/types/drawerName.ts
+++ b/src/types/drawerName.ts
@@ -8,4 +8,5 @@ export type DrawerName =
   | 'submaps'
   | 'reaction'
   | 'overlays'
-  | 'bio-entity';
+  | 'bio-entity'
+  | 'available-plugins';
diff --git a/src/types/iconTypes.ts b/src/types/iconTypes.ts
index c125f09c0ea0f1cb06bb15da4037fd4d1f8e56bf..3083f71695a3744b6638705a7ec79805bd8703c9 100644
--- a/src/types/iconTypes.ts
+++ b/src/types/iconTypes.ts
@@ -16,4 +16,5 @@ export type IconTypes =
   | 'location'
   | 'magnifier-zoom-in'
   | 'magnifier-zoom-out'
-  | 'pin';
+  | 'pin'
+  | 'three-dots';
diff --git a/src/types/modal.ts b/src/types/modal.ts
index 474c0f7aef86b9c6f5d0e83e6a924a7af323afbd..08b85048569414834c64481e4e8793335ffb0242 100644
--- a/src/types/modal.ts
+++ b/src/types/modal.ts
@@ -1 +1,7 @@
-export type ModalName = 'none' | 'overview-images' | 'mol-art' | 'login' | 'publications';
+export type ModalName =
+  | 'none'
+  | 'overview-images'
+  | 'mol-art'
+  | 'login'
+  | 'publications'
+  | 'edit-overlay';
diff --git a/src/types/models.ts b/src/types/models.ts
index 22862e3aa5f3270cd99643d33cc250ef837a5047..3f9efc0e75c9c1260b4572e642240f24c7b471a2 100644
--- a/src/types/models.ts
+++ b/src/types/models.ts
@@ -9,10 +9,12 @@ import {
   compartmentPathwaySchema,
 } from '@/models/compartmentPathwaySchema';
 import { configurationOptionSchema } from '@/models/configurationOptionSchema';
-import { configurationSchema, formatSchema } from '@/models/configurationSchema';
+import { configurationSchema, formatSchema, miriamTypesSchema } from '@/models/configurationSchema';
 import { disease } from '@/models/disease';
 import { drugSchema } from '@/models/drugSchema';
 import { elementSearchResult, elementSearchResultType } from '@/models/elementSearchResult';
+import { exportElementsSchema, exportNetworkchema } from '@/models/exportSchema';
+import { lineSchema } from '@/models/lineSchema';
 import { loginSchema } from '@/models/loginSchema';
 import { mapBackground } from '@/models/mapBackground';
 import {
@@ -23,13 +25,20 @@ import {
 } from '@/models/mapOverlay';
 import { mapModelSchema } from '@/models/modelSchema';
 import { organism } from '@/models/organism';
-import { overlayBioEntitySchema } from '@/models/overlayBioEntitySchema';
+import {
+  overlayBioEntitySchema,
+  overlayElementWithBioEntitySchema,
+  overlayElementWithReactionSchema,
+} from '@/models/overlayBioEntitySchema';
+import { overlayLeftBioEntitySchema } from '@/models/overlayLeftBioEntitySchema';
+import { overlayLeftReactionSchema } from '@/models/overlayLeftReactionSchema';
 import {
   overviewImageLink,
   overviewImageLinkImage,
   overviewImageLinkModel,
 } from '@/models/overviewImageLink';
 import { overviewImageView } from '@/models/overviewImageView';
+import { pluginSchema } from '@/models/pluginSchema';
 import { projectSchema } from '@/models/projectSchema';
 import { publicationSchema } from '@/models/publicationsSchema';
 import { reactionSchema } from '@/models/reaction';
@@ -66,7 +75,13 @@ export type Login = z.infer<typeof loginSchema>;
 export type ConfigurationOption = z.infer<typeof configurationOptionSchema>;
 export type Configuration = z.infer<typeof configurationSchema>;
 export type ConfigurationFormatSchema = z.infer<typeof formatSchema>;
+export type ConfigurationMiramiTypes = z.infer<typeof miriamTypesSchema>;
 export type OverlayBioEntity = z.infer<typeof overlayBioEntitySchema>;
+export type OverlayElementWithReaction = z.infer<typeof overlayElementWithReactionSchema>;
+export type OverlayElementWithBioEntity = z.infer<typeof overlayElementWithBioEntitySchema>;
+export type OverlayLeftBioEntity = z.infer<typeof overlayLeftBioEntitySchema>;
+export type OverlayLeftReaction = z.infer<typeof overlayLeftReactionSchema>;
+export type Line = z.infer<typeof lineSchema>;
 export type CreatedOverlayFile = z.infer<typeof createdOverlayFileSchema>;
 export type UploadedOverlayFileContent = z.infer<typeof uploadedOverlayFileContentSchema>;
 export type CreatedOverlay = z.infer<typeof createdOverlaySchema>;
@@ -76,3 +91,6 @@ export type CompartmentPathway = z.infer<typeof compartmentPathwaySchema>;
 export type CompartmentPathwayDetails = z.infer<typeof compartmentPathwayDetailsSchema>;
 export type PublicationsResponse = z.infer<typeof publicationsResponseSchema>;
 export type Publication = z.infer<typeof publicationSchema>;
+export type ExportNetwork = z.infer<typeof exportNetworkchema>;
+export type ExportElements = z.infer<typeof exportElementsSchema>;
+export type MinervaPlugin = z.infer<typeof pluginSchema>; // Plugin type interfers with global Plugin type
diff --git a/src/types/query.ts b/src/types/query.ts
index 98309123aeea5a80626fca86870beb56c6561ec3..be3453f011b515a134cf5aff62e1549ae31553c1 100644
--- a/src/types/query.ts
+++ b/src/types/query.ts
@@ -7,6 +7,7 @@ export interface QueryData {
   backgroundId?: number;
   initialPosition?: Partial<Point>;
   overlaysId?: number[];
+  pluginsId?: string[];
 }
 
 export interface QueryDataParams {
@@ -18,6 +19,7 @@ export interface QueryDataParams {
   y?: number;
   z?: number;
   overlaysId?: string;
+  pluginsId?: string;
 }
 
 export interface QueryDataRouterParams {
@@ -29,4 +31,5 @@ export interface QueryDataRouterParams {
   y?: string;
   z?: string;
   overlaysId?: string;
+  pluginsId?: string;
 }
diff --git a/src/utils/initialize/useInitializeStore.ts b/src/utils/initialize/useInitializeStore.ts
index 9722dd6173ea1fe82164f422f0b7d6dc106a22de..c648112775ac249fb74cc4ab3b439f803430297f 100644
--- a/src/utils/initialize/useInitializeStore.ts
+++ b/src/utils/initialize/useInitializeStore.ts
@@ -25,6 +25,7 @@ export const useInitializeStore = (): void => {
     if (isInitialized || !isQueryReady) {
       return;
     }
+
     dispatch(fetchInitialAppData({ queryData: parseQueryToTypes(query) }));
   }, [dispatch, isInitialized, query, isQueryReady, isInitDataLoadingFinished]);
 };
diff --git a/src/utils/number/numberToInt.ts b/src/utils/number/numberToInt.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b57608e083e67663a5e6552db0d227c4cbe6319c
--- /dev/null
+++ b/src/utils/number/numberToInt.ts
@@ -0,0 +1,10 @@
+import { ZERO } from '@/constants/common';
+
+export const numberToSafeInt = (num: number): number => {
+  // zero or NaN
+  if (!num) {
+    return ZERO;
+  }
+
+  return Number(num.toFixed(ZERO));
+};
diff --git a/src/utils/overlays/getOverlayReactionCoords.test.ts b/src/utils/overlays/getOverlayReactionCoords.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6d5d2ea1b023364c6ad7d5e06b0a5f062d5cec1c
--- /dev/null
+++ b/src/utils/overlays/getOverlayReactionCoords.test.ts
@@ -0,0 +1,85 @@
+import { OverlayReactionCoords } from '@/types/OLrendering';
+import { Line } from '@/types/models';
+import { getOverlayReactionCoordsFromLine } from './getOverlayReactionCoords';
+
+const LINE_DATA_BASE: Line = {
+  id: 66141,
+  width: 1,
+  color: {
+    alpha: 255,
+    rgb: -16777216,
+  },
+  z: 0,
+  segments: [
+    {
+      x1: 4457.375604345491,
+      y1: 7111.933125147456,
+      x2: 4462.61826820353,
+      y2: 7105.89040426431,
+    },
+  ],
+  startArrow: {
+    arrowType: 'NONE',
+    angle: 2.748893571891069,
+    lineType: 'SOLID',
+    length: 15,
+  },
+  endArrow: {
+    arrowType: 'NONE',
+    angle: 2.748893571891069,
+    lineType: 'SOLID',
+    length: 15,
+  },
+  lineType: 'SOLID',
+};
+
+describe('getOverlayReactionCoords - util', () => {
+  const cases: [Line, OverlayReactionCoords[]][] = [
+    [
+      {
+        ...LINE_DATA_BASE,
+        segments: [
+          {
+            x1: 10,
+            y1: 10,
+            x2: 100,
+            y2: 100,
+          },
+        ],
+      },
+      [{ height: -90, id: 66141, width: 90, x1: 10, x2: 100, y1: 10, y2: 100 }],
+    ],
+    [
+      {
+        ...LINE_DATA_BASE,
+        segments: [
+          {
+            x1: 10,
+            y1: 10,
+            x2: 2000,
+            y2: 0,
+          },
+        ],
+      },
+      [{ height: 10, id: 66141, width: 1990, x1: 10, x2: 2000, y1: 10, y2: 0 }],
+    ],
+    [
+      {
+        ...LINE_DATA_BASE,
+        segments: [
+          {
+            x1: 0,
+            y1: 0,
+            x2: 0,
+            y2: 0,
+          },
+        ],
+      },
+      [{ height: 0, id: 66141, width: 0, x1: 0, x2: 0, y1: 0, y2: 0 }],
+    ],
+  ];
+
+  it.each(cases)('should return valid result', (line, result) => {
+    expect(getOverlayReactionCoordsFromLine(line)).toStrictEqual(result);
+  });
+});
diff --git a/src/utils/overlays/getOverlayReactionCoords.ts b/src/utils/overlays/getOverlayReactionCoords.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c607fcde6e01f08334f0a38122646ec145fe17cc
--- /dev/null
+++ b/src/utils/overlays/getOverlayReactionCoords.ts
@@ -0,0 +1,14 @@
+import { OverlayReactionCoords } from '@/types/OLrendering';
+import { Line } from '@/types/models';
+
+export const getOverlayReactionCoordsFromLine = (line: Line): OverlayReactionCoords[] =>
+  line.segments.map(segment => {
+    const { x1, y1, x2, y2 } = segment;
+
+    return {
+      ...segment,
+      id: line.id,
+      width: x2 - x1,
+      height: y1 - y2,
+    };
+  });
diff --git a/src/utils/overlays/overlaysElementsTypeGuards.test.ts b/src/utils/overlays/overlaysElementsTypeGuards.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..19028e2c88aa16431ee269d267a531998004d189
--- /dev/null
+++ b/src/utils/overlays/overlaysElementsTypeGuards.test.ts
@@ -0,0 +1,35 @@
+import {
+  overlayElementWithBioEntityFixture,
+  overlayElementWithReactionFixture,
+} from '@/models/fixtures/overlayBioEntityFixture';
+import { isBioEntity, isReaction } from './overlaysElementsTypeGuards';
+
+describe('overlaysElementsTypeGruards - utils', () => {
+  describe('isReaction', () => {
+    describe('when is reaction', () => {
+      it('should return true', () => {
+        expect(isReaction(overlayElementWithReactionFixture)).toBe(true);
+      });
+    });
+
+    describe('when is bioentity', () => {
+      it('should return false', () => {
+        expect(isReaction(overlayElementWithBioEntityFixture)).toBe(false);
+      });
+    });
+  });
+
+  describe('isBioEntity', () => {
+    describe('when is reaction', () => {
+      it('should return false', () => {
+        expect(isBioEntity(overlayElementWithReactionFixture)).toBe(false);
+      });
+    });
+
+    describe('when is bioentity', () => {
+      it('should return true', () => {
+        expect(isBioEntity(overlayElementWithBioEntityFixture)).toBe(true);
+      });
+    });
+  });
+});
diff --git a/src/utils/overlays/overlaysElementsTypeGuards.ts b/src/utils/overlays/overlaysElementsTypeGuards.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6997b141f5d627b5d4641ee23c2f7b902f17a1af
--- /dev/null
+++ b/src/utils/overlays/overlaysElementsTypeGuards.ts
@@ -0,0 +1,14 @@
+import {
+  OverlayBioEntity,
+  OverlayElementWithBioEntity,
+  OverlayElementWithReaction,
+  OverlayLeftBioEntity,
+  OverlayLeftReaction,
+} from '@/types/models';
+
+export const isReaction = (e: OverlayBioEntity): e is OverlayElementWithReaction =>
+  (e.left as OverlayLeftReaction).line !== undefined;
+
+export const isBioEntity = (e: OverlayBioEntity): e is OverlayElementWithBioEntity =>
+  (e.left as OverlayLeftBioEntity).x !== undefined &&
+  (e.left as OverlayLeftBioEntity).y !== undefined;
diff --git a/src/utils/parseQueryToTypes.ts b/src/utils/parseQueryToTypes.ts
index ee7440375a4834e13cf217b9af5fd714889ec56b..f04abadfedebada9e8058ffa3d4eae08b9ffc731 100644
--- a/src/utils/parseQueryToTypes.ts
+++ b/src/utils/parseQueryToTypes.ts
@@ -11,4 +11,5 @@ export const parseQueryToTypes = (query: QueryDataRouterParams): QueryData => ({
     z: Number(query.z) || undefined,
   },
   overlaysId: query.overlaysId?.split(',').map(Number),
+  pluginsId: query.pluginsId?.split(',').map(String),
 });
diff --git a/src/utils/query-manager/useReduxBusQueryManager.test.ts b/src/utils/query-manager/useReduxBusQueryManager.test.ts
index 77244318601a6d608b143772ca813e7e390e4eaf..c77f8f3fbccbb56fdf3ace53f190b29b6ca62598 100644
--- a/src/utils/query-manager/useReduxBusQueryManager.test.ts
+++ b/src/utils/query-manager/useReduxBusQueryManager.test.ts
@@ -29,6 +29,19 @@ describe('useReduxBusQueryManager - util', () => {
         loading: 'idle' as Loading,
         error: { name: '', message: '' },
       },
+      userOverlays: {
+        data: [],
+        loading: 'idle' as Loading,
+        error: { name: '', message: '' },
+      },
+      updateOverlays: {
+        loading: 'idle' as Loading,
+        error: { name: '', message: '' },
+      },
+      removeOverlay: {
+        loading: 'idle' as Loading,
+        error: { name: '', message: '' },
+      },
     };
 
     const { Wrapper } = getReduxWrapperWithStore({
diff --git a/src/utils/query-manager/useReduxBusQueryManager.ts b/src/utils/query-manager/useReduxBusQueryManager.ts
index 80d277dd03a6954af2085dbc98fe7c75cf169663..5a2a58772b7543ac5d79ced941ed15fb5b9e6834 100644
--- a/src/utils/query-manager/useReduxBusQueryManager.ts
+++ b/src/utils/query-manager/useReduxBusQueryManager.ts
@@ -11,10 +11,10 @@ export const useReduxBusQueryManager = (): void => {
 
   const handleChangeQuery = useCallback(
     () =>
+      // eslint-disable-next-line react-hooks/exhaustive-deps
       router.replace(
         {
           query: {
-            ...router.query,
             ...queryData,
           },
         },
@@ -23,7 +23,6 @@ export const useReduxBusQueryManager = (): void => {
           shallow: true,
         },
       ),
-    // router is not an stable reference
     // eslint-disable-next-line react-hooks/exhaustive-deps
     [queryData],
   );