diff --git a/frontend/src/app/main/data/exports.cljs b/frontend/src/app/main/data/exports/assets.cljs
similarity index 99%
rename from frontend/src/app/main/data/exports.cljs
rename to frontend/src/app/main/data/exports/assets.cljs
index ebea22149..9df77afda 100644
--- a/frontend/src/app/main/data/exports.cljs
+++ b/frontend/src/app/main/data/exports/assets.cljs
@@ -4,7 +4,7 @@
 ;;
 ;; Copyright (c) KALEIDOS INC
 
-(ns app.main.data.exports
+(ns app.main.data.exports.assets
   (:require
    [app.common.uuid :as uuid]
    [app.main.data.modal :as modal]
diff --git a/frontend/src/app/main/data/exports/files.cljs b/frontend/src/app/main/data/exports/files.cljs
new file mode 100644
index 000000000..534ab209d
--- /dev/null
+++ b/frontend/src/app/main/data/exports/files.cljs
@@ -0,0 +1,89 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.main.data.exports.files
+  "The file exportation API and events"
+  (:require
+   [app.common.data :as d]
+   [app.common.data.macros :as dm]
+   [app.common.schema :as sm]
+   [app.main.data.events :as ev]
+   [app.main.data.modal :as modal]
+   [app.main.features :as features]
+   [app.main.repo :as rp]
+   [beicon.v2.core :as rx]
+   [potok.v2.core :as ptk]))
+
+(def valid-types
+  (d/ordered-set :all :merge :detach))
+
+(def valid-formats
+  #{:binfile-v1 :binfile-v3 :legacy-zip})
+
+(def ^:private schema:export-files
+  [:sequential {:title "Files"}
+   [:map {:title "FileParam"}
+    [:id ::sm/uuid]
+    [:name :string]
+    [:project-id ::sm/uuid]
+    [:is-shared ::sm/boolean]]])
+
+(def check-export-files!
+  (sm/check-fn schema:export-files))
+
+(defn export-files
+  [files format]
+  (dm/assert!
+   "expected valid files param"
+   (check-export-files! files))
+
+  (dm/assert!
+   "expected valid format"
+   (contains? valid-formats format))
+
+  (ptk/reify ::export-files
+    ptk/WatchEvent
+    (watch [_ state _]
+      (let [features (features/get-team-enabled-features state)
+            team-id  (:current-team-id state)
+            evname   (if (= format :legacy-zip)
+                       "export-standard-files"
+                       "export-binary-files")]
+
+        (rx/merge
+         (rx/of (ptk/event ::ev/event {::ev/name evname
+                                       ::ev/origin "dashboard"
+                                       :format format
+                                       :num-files (count files)}))
+         (->> (rx/from files)
+              (rx/mapcat
+               (fn [file]
+                 (->> (rp/cmd! :has-file-libraries {:file-id (:id file)})
+                      (rx/map #(assoc file :has-libraries %)))))
+              (rx/reduce conj [])
+              (rx/map (fn [files]
+                        (modal/show
+                         {:type ::export-files
+                          :features features
+                          :team-id team-id
+                          :files files
+                          :format format})))))))))
+
+;;;;;;;;;;;;;;;;;;;;;;
+;; Team Request
+;;;;;;;;;;;;;;;;;;;;;;
+
+(defn create-team-access-request
+  [params]
+  (ptk/reify ::create-team-access-request
+    ptk/WatchEvent
+    (watch [_ _ _]
+      (let [{:keys [on-success on-error]
+             :or {on-success identity
+                  on-error rx/throw}} (meta params)]
+        (->> (rp/cmd! :create-team-access-request params)
+             (rx/tap on-success)
+             (rx/catch on-error))))))
diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs
index 03f27594c..694143e40 100644
--- a/frontend/src/app/main/data/workspace/shortcuts.cljs
+++ b/frontend/src/app/main/data/workspace/shortcuts.cljs
@@ -8,7 +8,7 @@
   (:require
    [app.common.data.macros :as dm]
    [app.main.data.events :as ev]
-   [app.main.data.exports :as de]
+   [app.main.data.exports.assets :as de]
    [app.main.data.modal :as modal]
    [app.main.data.plugins :as dpl]
    [app.main.data.preview :as dp]
diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs
index 1294bbe8e..17ce25d75 100644
--- a/frontend/src/app/main/ui.cljs
+++ b/frontend/src/app/main/ui.cljs
@@ -11,6 +11,7 @@
    [app.main.ui.context :as ctx]
    [app.main.ui.debug.icons-preview :refer [icons-preview]]
    [app.main.ui.error-boundary :refer [error-boundary*]]
+   [app.main.ui.exports.files]
    [app.main.ui.frame-preview :as frame-preview]
    [app.main.ui.icons :as i]
    [app.main.ui.notifications :as notifications]
diff --git a/frontend/src/app/main/ui/dashboard/file_menu.cljs b/frontend/src/app/main/ui/dashboard/file_menu.cljs
index df91e5c9c..7d133dbc3 100644
--- a/frontend/src/app/main/ui/dashboard/file_menu.cljs
+++ b/frontend/src/app/main/ui/dashboard/file_menu.cljs
@@ -9,7 +9,8 @@
    [app.config :as cf]
    [app.main.data.common :as dcm]
    [app.main.data.dashboard :as dd]
-   [app.main.data.events :as ev]
+   [app.main.data.events :as-alias ev]
+   [app.main.data.exports.files :as fexp]
    [app.main.data.modal :as modal]
    [app.main.data.notifications :as ntf]
    [app.main.refs :as refs]
@@ -21,7 +22,6 @@
    [app.util.i18n :as i18n :refer [tr]]
    [app.util.router :as rt]
    [beicon.v2.core :as rx]
-   [potok.v2.core :as ptk]
    [rumext.v2 :as mf]))
 
 (defn get-project-name
@@ -191,14 +191,8 @@
         (mf/use-fn
          (mf/deps files)
          (fn [format]
-           (let [evname (if (= format :legacy-zip)
-                          "export-standard-files"
-                          "export-binary-files")]
-             (st/emit! (ptk/event ::ev/event {::ev/name evname
-                                              ::ev/origin "dashboard"
-                                              :format format
-                                              :num-files (count files)})
-                       (dcm/export-files files format)))))
+           (st/emit! (with-meta (fexp/export-files files format)
+                       {::ev/origin "dashboard"}))))
 
         on-export-binary-files
         (mf/use-fn
diff --git a/frontend/src/app/main/ui/export.cljs b/frontend/src/app/main/ui/exports/assets.cljs
similarity index 64%
rename from frontend/src/app/main/ui/export.cljs
rename to frontend/src/app/main/ui/exports/assets.cljs
index e38aae881..a2d343a49 100644
--- a/frontend/src/app/main/ui/export.cljs
+++ b/frontend/src/app/main/ui/exports/assets.cljs
@@ -4,7 +4,8 @@
 ;;
 ;; Copyright (c) KALEIDOS INC
 
-(ns app.main.ui.export
+;; FIXME: rename
+(ns app.main.ui.exports.assets
   "Assets exportation common components."
   (:require-macros [app.main.style :as stl])
   (:require
@@ -12,18 +13,15 @@
    [app.common.data :as d]
    [app.common.data.macros :as dm]
    [app.main.data.events :as ev]
-   [app.main.data.exports :as de]
+   [app.main.data.exports.assets :as de]
    [app.main.data.modal :as modal]
    [app.main.refs :as refs]
    [app.main.store :as st]
-   [app.main.ui.ds.product.loader :refer [loader*]]
    [app.main.ui.icons :as i]
    [app.main.ui.workspace.shapes :refer [shape-wrapper]]
-   [app.main.worker :as uw]
    [app.util.dom :as dom]
    [app.util.i18n :as i18n :refer  [tr c]]
    [app.util.strings :as ust]
-   [beicon.v2.core :as rx]
    [cuerdas.core :as str]
    [potok.v2.core :as ptk]
    [rumext.v2 :as mf]))
@@ -313,187 +311,3 @@
                     :stroke-dasharray 280
                     :stroke-dashoffset (- 280 pwidth)
                     :style {:transition "stroke-dashoffset 1s ease-in-out"}}]]])])]))
-
-(mf/defc export-entry
-  {::mf/wrap-props false}
-  [{:keys [file]}]
-  [:div {:class (stl/css-case :file-entry true
-                              :loading  (:loading file)
-                              :success  (:export-success? file)
-                              :error    (:export-error? file))}
-
-   [:div {:class (stl/css :file-name)}
-    (if (:loading file)
-      [:> loader*  {:width 16
-                    :title (tr "labels.loading")}]
-      [:span {:class (stl/css :file-icon)}
-       (cond (:export-success? file) i/tick
-             (:export-error? file)   i/close)])
-
-    [:div {:class (stl/css :file-name-label)}
-     (:name file)]]])
-
-(defn- mark-file-error
-  [files file-id]
-  (mapv #(cond-> %
-           (= file-id (:id %))
-           (assoc :export-error? true
-                  :loading false))
-        files))
-
-(defn- mark-file-success
-  [files file-id]
-  (mapv #(cond-> %
-           (= file-id (:id %))
-           (assoc :export-success? true
-                  :loading false))
-        files))
-
-(defn- initialize-state
-  "Initialize export dialog state"
-  [files]
-  (let [files (mapv (fn [file] (assoc file :loading true)) files)]
-    {:status :prepare
-     :selected :all
-     :files files}))
-
-(def default-export-types
-  (d/ordered-set :all :merge :detach))
-
-(mf/defc export-dialog
-  {::mf/register modal/components
-   ::mf/register-as :export
-   ::mf/wrap-props false}
-  [{:keys [team-id files features format]}]
-  (let [state*          (mf/use-state (partial initialize-state files))
-        has-libs?       (some :has-libraries files)
-
-        state           (deref state*)
-        selected        (:selected state)
-        status          (:status state)
-
-        binary?         (not= format :legacy-zip)
-
-        ;; We've deprecated the merge option on non-binary files
-        ;; because it wasn't working and we're planning to remove this
-        ;; export in future releases.
-        export-types (if binary? default-export-types [:all :detach])
-
-        start-export
-        (mf/use-fn
-         (mf/deps team-id selected files features)
-         (fn []
-           (swap! state* assoc :status :exporting)
-           (->> (uw/ask-many!
-                 {:cmd :export-files
-                  :format format
-                  :team-id team-id
-                  :features features
-                  :type selected
-                  :files files})
-                (rx/mapcat #(->> (rx/of %)
-                                 (rx/delay 1000)))
-                (rx/subs!
-                 (fn [msg]
-                   (cond
-                     (= :error (:type msg))
-                     (swap! state* update :files mark-file-error (:file-id msg))
-
-                     (= :finish (:type msg))
-                     (do
-                       (swap! state* update :files mark-file-success (:file-id msg))
-                       (dom/trigger-download-uri (:filename msg) (:mtype msg) (:uri msg)))))))))
-
-        on-cancel
-        (mf/use-fn
-         (fn [event]
-           (dom/prevent-default event)
-           (st/emit! (modal/hide))))
-
-        on-accept
-        (mf/use-fn
-         (mf/deps start-export)
-         (fn [event]
-           (dom/prevent-default event)
-           (start-export)))
-
-        on-change
-        (mf/use-fn
-         (fn [event]
-           (let [type (-> (dom/get-target event)
-                          (dom/get-data "type")
-                          (keyword))]
-             (swap! state* assoc :selected type))))]
-
-    (mf/with-effect [has-libs?]
-      ;; Start download automatically when no libraries
-      (when-not has-libs?
-        (start-export)))
-
-    [:div {:class (stl/css :modal-overlay)}
-     [:div {:class (stl/css :modal-container)}
-      [:div {:class (stl/css :modal-header)}
-       [:h2 {:class (stl/css :modal-title)}
-        (tr "dashboard.export.title")]
-       [:button {:class (stl/css :modal-close-btn)
-                 :on-click on-cancel} i/close]]
-
-      (cond
-        (= status :prepare)
-        [:*
-         [:div {:class (stl/css :modal-content)}
-          [:p {:class (stl/css :modal-msg)} (tr "dashboard.export.explain")]
-          [:p {:class (stl/css :modal-scd-msg)} (tr "dashboard.export.detail")]
-
-          (for [type export-types]
-            [:div {:class (stl/css :export-option true)
-                   :key (name type)}
-             [:label {:for (str "export-" type)
-                      :class (stl/css-case :global/checked (= selected type))}
-              ;; Execution time translation strings:
-              ;;   (tr "dashboard.export.options.all.message")
-              ;;   (tr "dashboard.export.options.all.title")
-              ;;   (tr "dashboard.export.options.detach.message")
-              ;;   (tr "dashboard.export.options.detach.title")
-              ;;   (tr "dashboard.export.options.merge.message")
-              ;;   (tr "dashboard.export.options.merge.title")
-              [:span {:class (stl/css-case :global/checked (= selected type))}
-               (when (= selected type)
-                 i/status-tick)]
-              [:div {:class (stl/css :option-content)}
-               [:h3 {:class (stl/css :modal-subtitle)} (tr (dm/str "dashboard.export.options." (d/name type) ".title"))]
-               [:p  {:class (stl/css :modal-msg)} (tr (dm/str "dashboard.export.options." (d/name type) ".message"))]]
-
-              [:input {:type "radio"
-                       :class (stl/css :option-input)
-                       :id (str "export-" type)
-                       :checked (= selected type)
-                       :name "export-option"
-                       :data-type (name type)
-                       :on-change on-change}]]])]
-
-         [:div {:class (stl/css :modal-footer)}
-          [:div {:class (stl/css :action-buttons)}
-           [:input {:class (stl/css :cancel-button)
-                    :type "button"
-                    :value (tr "labels.cancel")
-                    :on-click on-cancel}]
-
-           [:input {:class (stl/css :accept-btn)
-                    :type "button"
-                    :value (tr "labels.continue")
-                    :on-click on-accept}]]]]
-
-        (= status :exporting)
-        [:*
-         [:div {:class (stl/css :modal-content)}
-          (for [file (:files state)]
-            [:& export-entry {:file file :key (dm/str (:id file))}])]
-
-         [:div {:class (stl/css :modal-footer)}
-          [:div {:class (stl/css :action-buttons)}
-           [:input {:class (stl/css :accept-btn)
-                    :type "button"
-                    :value (tr "labels.close")
-                    :disabled (->> state :files (some :loading))
-                    :on-click on-cancel}]]]])]]))
diff --git a/frontend/src/app/main/ui/export.scss b/frontend/src/app/main/ui/exports/assets.scss
similarity index 100%
rename from frontend/src/app/main/ui/export.scss
rename to frontend/src/app/main/ui/exports/assets.scss
diff --git a/frontend/src/app/main/ui/exports/files.cljs b/frontend/src/app/main/ui/exports/files.cljs
new file mode 100644
index 000000000..bbc954a57
--- /dev/null
+++ b/frontend/src/app/main/ui/exports/files.cljs
@@ -0,0 +1,207 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.main.ui.exports.files
+  "The files export dialog/modal"
+  (:require-macros [app.main.style :as stl])
+  (:require
+   [app.common.data :as d]
+   [app.common.data.macros :as dm]
+   [app.main.data.exports.files :as fexp]
+   [app.main.data.modal :as modal]
+   [app.main.store :as st]
+   [app.main.ui.ds.product.loader :refer [loader*]]
+   [app.main.ui.icons :as i]
+   [app.main.worker :as uw]
+   [app.util.dom :as dom]
+   [app.util.i18n :as i18n :refer  [tr]]
+   [beicon.v2.core :as rx]
+   [rumext.v2 :as mf]))
+
+(defn- mark-file-error
+  [files file-id]
+  (mapv #(cond-> %
+           (= file-id (:id %))
+           (assoc :export-error? true
+                  :loading false))
+        files))
+
+(defn- mark-file-success
+  [files file-id]
+  (mapv #(cond-> %
+           (= file-id (:id %))
+           (assoc :export-success? true
+                  :loading false))
+        files))
+
+(defn- initialize-state
+  "Initialize export dialog state"
+  [files]
+  (let [files (mapv (fn [file] (assoc file :loading true)) files)]
+    {:status :prepare
+     :selected :all
+     :files files}))
+
+(mf/defc export-entry*
+  {::mf/props :obj
+   ::mf/private true}
+  [{:keys [file]}]
+  [:div {:class (stl/css-case
+                 :file-entry true
+                 :loading  (:loading file)
+                 :success  (:export-success? file)
+                 :error    (:export-error? file))}
+
+   [:div {:class (stl/css :file-name)}
+    (if (:loading file)
+      [:> loader*  {:width 16
+                    :title (tr "labels.loading")}]
+      [:span {:class (stl/css :file-icon)}
+       (cond (:export-success? file) i/tick
+             (:export-error? file)   i/close)])
+
+    [:div {:class (stl/css :file-name-label)}
+     (:name file)]]])
+
+(mf/defc export-dialog*
+  {::mf/register modal/components
+   ::mf/register-as ::fexp/export-files
+   ::mf/props :obj}
+  [{:keys [team-id files features format]}]
+  (let [state*       (mf/use-state (partial initialize-state files))
+        has-libs?    (some :has-libraries files)
+
+        state        (deref state*)
+        selected     (:selected state)
+        status       (:status state)
+
+        binary?      (not= format :legacy-zip)
+
+        ;; We've deprecated the merge option on non-binary files
+        ;; because it wasn't working and we're planning to remove this
+        ;; export in future releases.
+        export-types (if binary? fexp/valid-types [:all :detach])
+
+        start-export
+        (mf/use-fn
+         (mf/deps team-id selected files features)
+         (fn []
+           (swap! state* assoc :status :exporting)
+           (->> (uw/ask-many!
+                 {:cmd :export-files
+                  :format format
+                  :team-id team-id
+                  :features features
+                  :type selected
+                  :files files})
+                (rx/mapcat #(->> (rx/of %)
+                                 (rx/delay 1000)))
+                (rx/subs!
+                 (fn [msg]
+                   (cond
+                     (= :error (:type msg))
+                     (swap! state* update :files mark-file-error (:file-id msg))
+
+                     (= :finish (:type msg))
+                     (do
+                       (swap! state* update :files mark-file-success (:file-id msg))
+                       (dom/trigger-download-uri (:filename msg) (:mtype msg) (:uri msg)))))))))
+
+        on-cancel
+        (mf/use-fn
+         (fn [event]
+           (dom/prevent-default event)
+           (st/emit! (modal/hide))))
+
+        on-accept
+        (mf/use-fn
+         (mf/deps start-export)
+         (fn [event]
+           (dom/prevent-default event)
+           (start-export)))
+
+        on-change
+        (mf/use-fn
+         (fn [event]
+           (let [type (-> (dom/get-target event)
+                          (dom/get-data "type")
+                          (keyword))]
+             (swap! state* assoc :selected type))))]
+
+    (mf/with-effect [has-libs?]
+      ;; Start download automatically when no libraries
+      (when-not has-libs?
+        (start-export)))
+
+    [:div {:class (stl/css :modal-overlay)}
+     [:div {:class (stl/css :modal-container)}
+      [:div {:class (stl/css :modal-header)}
+       [:h2 {:class (stl/css :modal-title)}
+        (tr "dashboard.export.title")]
+       [:button {:class (stl/css :modal-close-btn)
+                 :on-click on-cancel} i/close]]
+
+      (cond
+        (= status :prepare)
+        [:*
+         [:div {:class (stl/css :modal-content)}
+          [:p {:class (stl/css :modal-msg)} (tr "dashboard.export.explain")]
+          [:p {:class (stl/css :modal-scd-msg)} (tr "dashboard.export.detail")]
+
+          (for [type export-types]
+            [:div {:class (stl/css :export-option true)
+                   :key (name type)}
+             [:label {:for (str "export-" type)
+                      :class (stl/css-case :global/checked (= selected type))}
+              ;; Execution time translation strings:
+              ;;   (tr "dashboard.export.options.all.message")
+              ;;   (tr "dashboard.export.options.all.title")
+              ;;   (tr "dashboard.export.options.detach.message")
+              ;;   (tr "dashboard.export.options.detach.title")
+              ;;   (tr "dashboard.export.options.merge.message")
+              ;;   (tr "dashboard.export.options.merge.title")
+              [:span {:class (stl/css-case :global/checked (= selected type))}
+               (when (= selected type)
+                 i/status-tick)]
+              [:div {:class (stl/css :option-content)}
+               [:h3 {:class (stl/css :modal-subtitle)}
+                (tr (dm/str "dashboard.export.options." (d/name type) ".title"))]
+               [:p  {:class (stl/css :modal-msg)}
+                (tr (dm/str "dashboard.export.options." (d/name type) ".message"))]]
+
+              [:input {:type "radio"
+                       :class (stl/css :option-input)
+                       :id (str "export-" type)
+                       :checked (= selected type)
+                       :name "export-option"
+                       :data-type (name type)
+                       :on-change on-change}]]])]
+
+         [:div {:class (stl/css :modal-footer)}
+          [:div {:class (stl/css :action-buttons)}
+           [:input {:class (stl/css :cancel-button)
+                    :type "button"
+                    :value (tr "labels.cancel")
+                    :on-click on-cancel}]
+
+           [:input {:class (stl/css :accept-btn)
+                    :type "button"
+                    :value (tr "labels.continue")
+                    :on-click on-accept}]]]]
+
+        (= status :exporting)
+        [:*
+         [:div {:class (stl/css :modal-content)}
+          (for [file (:files state)]
+            [:> export-entry* {:file file :key (dm/str (:id file))}])]
+
+         [:div {:class (stl/css :modal-footer)}
+          [:div {:class (stl/css :action-buttons)}
+           [:input {:class (stl/css :accept-btn)
+                    :type "button"
+                    :value (tr "labels.close")
+                    :disabled (->> state :files (some :loading))
+                    :on-click on-cancel}]]]])]]))
diff --git a/frontend/src/app/main/ui/exports/files.scss b/frontend/src/app/main/ui/exports/files.scss
new file mode 100644
index 000000000..c95f6b64a
--- /dev/null
+++ b/frontend/src/app/main/ui/exports/files.scss
@@ -0,0 +1,237 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Copyright (c) KALEIDOS INC
+
+@import "refactor/common-refactor.scss";
+
+// EXPORT MODAL
+.modal-overlay {
+  @extend .modal-overlay-base;
+  &.transparent {
+    background-color: transparent;
+  }
+}
+
+.modal-container {
+  @extend .modal-container-base;
+  max-height: calc(10 * $s-80);
+}
+
+.modal-header {
+  margin-bottom: $s-24;
+}
+
+.modal-title {
+  @include headlineMediumTypography;
+  color: var(--modal-title-foreground-color);
+}
+
+.modal-close-btn {
+  @extend .modal-close-btn-base;
+}
+
+.modal-content,
+.no-selection {
+  @include bodySmallTypography;
+  margin-bottom: $s-24;
+  .modal-hint {
+    @include bodySmallTypography;
+    color: var(--modal-text-foreground-color);
+  }
+  .modal-link {
+    @include bodyLargeTypography;
+    text-decoration: none;
+    cursor: pointer;
+    color: var(--modal-link-foreground-color);
+  }
+  .selection-header {
+    @include flexRow;
+    height: $s-32;
+    margin-bottom: $s-4;
+    .selection-btn {
+      @include buttonStyle;
+      @extend .input-checkbox;
+      @include flexCenter;
+      height: $s-24;
+      width: $s-24;
+      padding: 0;
+      margin-left: $s-16;
+      span {
+        @extend .checkbox-icon;
+      }
+    }
+    .selection-title {
+      @include bodyLargeTypography;
+      color: var(--modal-text-foreground-color);
+    }
+  }
+  .selection-wrapper {
+    position: relative;
+    width: 100%;
+    height: fit-content;
+  }
+  .selection-shadow {
+    width: 100%;
+    height: 100%;
+    &:after {
+      position: absolute;
+      bottom: 0;
+      left: 0;
+      width: 100%;
+      height: 50px;
+      background: linear-gradient(to top, rgba(24, 24, 26, 1) 0%, rgba(24, 24, 26, 0) 100%);
+      content: "";
+      pointer-events: none;
+    }
+  }
+  .selection-list {
+    @include flexColumn;
+    max-height: $s-400;
+    overflow-y: auto;
+    padding-bottom: $s-12;
+    .selection-row {
+      @include flexRow;
+      background-color: var(--entry-background-color);
+      min-height: $s-40;
+      border-radius: $br-8;
+      .selection-btn {
+        @include buttonStyle;
+        display: grid;
+        grid-template-columns: min-content auto 1fr auto auto;
+        align-items: center;
+        width: 100%;
+        height: 10%;
+        gap: $s-8;
+        padding: 0 $s-16;
+        .checkbox-wrapper {
+          @extend .input-checkbox;
+          @include flexCenter;
+          height: $s-24;
+          width: $s-24;
+          padding: 0;
+          .checkobox-tick {
+            @extend .checkbox-icon;
+          }
+        }
+        .selection-name {
+          @include bodyLargeTypography;
+          @include textEllipsis;
+          flex-grow: 1;
+          color: var(--modal-text-foreground-color);
+          text-align: start;
+        }
+        .selection-scale {
+          @include bodyLargeTypography;
+          @include textEllipsis;
+          min-width: $s-108;
+          padding: $s-12;
+          color: var(--modal-text-foreground-color);
+        }
+        .selection-extension {
+          @include bodyLargeTypography;
+          @include textEllipsis;
+          min-width: $s-72;
+          padding: $s-12;
+          color: var(--modal-text-foreground-color);
+        }
+      }
+      .image-wrapper {
+        @include flexCenter;
+        min-height: $s-32;
+        min-width: $s-32;
+        background-color: var(--app-white);
+        border-radius: $br-6;
+        margin: auto 0;
+        img,
+        svg {
+          object-fit: contain;
+          max-height: $s-40;
+        }
+      }
+    }
+  }
+}
+
+.action-buttons {
+  @extend .modal-action-btns;
+}
+.cancel-button {
+  @extend .modal-cancel-btn;
+}
+.accept-btn {
+  @extend .modal-accept-btn;
+  &.danger {
+    @extend .modal-danger-btn;
+  }
+}
+
+.modal-scd-msg,
+.modal-subtitle,
+.modal-msg {
+  @include bodyLargeTypography;
+  color: var(--modal-text-foreground-color);
+}
+
+.export-option {
+  @extend .input-checkbox;
+  width: 100%;
+  align-items: flex-start;
+  label {
+    align-items: flex-start;
+    .modal-subtitle {
+      @include bodyLargeTypography;
+      color: var(--modal-title-foreground-color);
+      padding: 0.25rem 0;
+    }
+  }
+  span {
+    margin-top: $s-8;
+  }
+}
+
+.option-content {
+  @include flexColumn;
+  @include bodyLargeTypography;
+}
+
+.file-entry {
+  .file-name {
+    @include flexRow;
+    .file-icon {
+      @include flexCenter;
+      height: $s-16;
+      width: $s-16;
+
+      svg {
+        @extend .button-icon-small;
+        stroke: var(--input-foreground);
+      }
+    }
+    .file-name-label {
+      @include bodyLargeTypography;
+    }
+  }
+  &.loading {
+    .file-name {
+      color: var(--modal-text-foreground-color);
+    }
+  }
+  &.error {
+    .file-name {
+      color: var(--modal-text-foreground-color);
+      .file-icon svg {
+        stroke: var(--modal-text-foreground-color);
+      }
+    }
+  }
+  &.success {
+    .file-name {
+      color: var(--modal-text-foreground-color);
+      .file-icon svg {
+        stroke: var(--modal-text-foreground-color);
+      }
+    }
+  }
+}
diff --git a/frontend/src/app/main/ui/viewer/header.cljs b/frontend/src/app/main/ui/viewer/header.cljs
index 9270c5aa6..6db8a69b9 100644
--- a/frontend/src/app/main/ui/viewer/header.cljs
+++ b/frontend/src/app/main/ui/viewer/header.cljs
@@ -14,7 +14,7 @@
    [app.main.data.viewer.shortcuts :as sc]
    [app.main.store :as st]
    [app.main.ui.components.dropdown :refer [dropdown]]
-   [app.main.ui.export :refer [export-progress-widget]]
+   [app.main.ui.exports.assets :refer [export-progress-widget]]
    [app.main.ui.formats :as fmt]
    [app.main.ui.icons :as i]
    [app.main.ui.viewer.comments :refer [comments-menu]]
diff --git a/frontend/src/app/main/ui/viewer/inspect/exports.cljs b/frontend/src/app/main/ui/viewer/inspect/exports.cljs
index 2e38efd40..41b81a523 100644
--- a/frontend/src/app/main/ui/viewer/inspect/exports.cljs
+++ b/frontend/src/app/main/ui/viewer/inspect/exports.cljs
@@ -9,7 +9,7 @@
   (:require
    [app.common.data :as d]
    [app.main.data.events :as ev]
-   [app.main.data.exports :as de]
+   [app.main.data.exports.assets :as de]
    [app.main.refs :as refs]
    [app.main.store :as st]
    [app.main.ui.components.select :refer [select]]
diff --git a/frontend/src/app/main/ui/workspace/main_menu.cljs b/frontend/src/app/main/ui/workspace/main_menu.cljs
index e2feeba89..19545708d 100644
--- a/frontend/src/app/main/ui/workspace/main_menu.cljs
+++ b/frontend/src/app/main/ui/workspace/main_menu.cljs
@@ -14,7 +14,8 @@
    [app.config :as cf]
    [app.main.data.common :as dcm]
    [app.main.data.events :as ev]
-   [app.main.data.exports :as de]
+   [app.main.data.exports.assets :as de]
+   [app.main.data.exports.files :as fexp]
    [app.main.data.modal :as modal]
    [app.main.data.plugins :as dp]
    [app.main.data.shortcuts :as scd]
@@ -527,16 +528,9 @@
          (fn [event]
            (let [target  (dom/get-current-target event)
                  format  (-> (dom/get-data target "format")
-                             (keyword))
-                 evname  (if (= format :legacy-zip)
-                           "export-standard-files"
-                           "export-binary-files")]
-             (st/emit!
-              (ptk/event ::ev/event {::ev/name evname
-                                     ::ev/origin "workspace"
-                                     :format format
-                                     :num-files 1})
-              (dcm/export-files [file] format)))))
+                             (keyword))]
+             (st/emit! (st/emit! (with-meta (fexp/export-files [file] format)
+                                   {::ev/origin "workspace"}))))))
 
         on-export-file-key-down
         (mf/use-fn
diff --git a/frontend/src/app/main/ui/workspace/right_header.cljs b/frontend/src/app/main/ui/workspace/right_header.cljs
index 775de4b9b..f9e2e3252 100644
--- a/frontend/src/app/main/ui/workspace/right_header.cljs
+++ b/frontend/src/app/main/ui/workspace/right_header.cljs
@@ -16,7 +16,7 @@
    [app.main.store :as st]
    [app.main.ui.components.dropdown :refer [dropdown]]
    [app.main.ui.context :as ctx]
-   [app.main.ui.export :refer [export-progress-widget]]
+   [app.main.ui.exports.assets :refer [export-progress-widget]]
    [app.main.ui.formats :as fmt]
    [app.main.ui.icons :as i]
    [app.main.ui.workspace.presence :refer [active-sessions]]
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs
index 13133cc47..bcec78142 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs
@@ -9,14 +9,14 @@
   (:require
    [app.common.data :as d]
    [app.main.data.events :as ev]
-   [app.main.data.exports :as de]
+   [app.main.data.exports.assets :as de]
    [app.main.data.workspace.shapes :as dwsh]
    [app.main.data.workspace.state-helpers :as wsh]
    [app.main.refs :as refs]
    [app.main.store :as st]
    [app.main.ui.components.select :refer [select]]
    [app.main.ui.components.title-bar :refer [title-bar]]
-   [app.main.ui.export]
+   [app.main.ui.exports.assets]
    [app.main.ui.icons :as i]
    [app.util.dom :as dom]
    [app.util.i18n :refer  [tr c]]
diff --git a/frontend/src/app/plugins/file.cljs b/frontend/src/app/plugins/file.cljs
index 0fb3c80bb..b80fc2b3f 100644
--- a/frontend/src/app/plugins/file.cljs
+++ b/frontend/src/app/plugins/file.cljs
@@ -10,10 +10,10 @@
    [app.common.record :as crc]
    [app.common.uuid :as uuid]
    [app.config :as cf]
+   [app.main.data.exports.files :as exports.files]
    [app.main.data.workspace :as dw]
    [app.main.features :as features]
    [app.main.store :as st]
-   [app.main.ui.export :as mue]
    [app.main.worker :as uw]
    [app.plugins.page :as page]
    [app.plugins.parser :as parser]
@@ -121,7 +121,7 @@
         (not (contains? #{"penpot" "zip"} format))
         (u/display-not-valid :format type)
 
-        (not (contains? (set mue/default-export-types) type))
+        (not (contains? (set exports.files/valid-types) type))
         (u/display-not-valid :type type)
 
         :else