diff --git a/packages/ui/src/components/Popup.svelte b/packages/ui/src/components/Popup.svelte
index ba29b77db7..68d15a1790 100644
--- a/packages/ui/src/components/Popup.svelte
+++ b/packages/ui/src/components/Popup.svelte
@@ -30,20 +30,18 @@
 {#if $modal.length > 0}
   <slot name="popup-header" />
 {/if}
-{#each $modal as popup, i}
-  {#key popup.id}
-    <PopupInstance
-      bind:this={instances[i]}
-      is={popup.is}
-      props={popup.props}
-      element={popup.element}
-      onClose={popup.onClose}
-      onUpdate={popup.onUpdate}
-      zIndex={(i + 1) * 500}
-      top={$modal.length - 1 === i}
-      close={popup.close}
-      {contentPanel}
-      overlay={popup.options.overlay}
-    />
-  {/key}
+{#each $modal as popup, i (popup.id)}
+  <PopupInstance
+    bind:this={instances[i]}
+    is={popup.is}
+    props={popup.props}
+    element={popup.element}
+    onClose={popup.onClose}
+    onUpdate={popup.onUpdate}
+    zIndex={(i + 1) * 500}
+    top={$modal.length - 1 === i}
+    close={popup.close}
+    {contentPanel}
+    overlay={popup.options.overlay}
+  />
 {/each}
diff --git a/packages/ui/src/components/PopupInstance.svelte b/packages/ui/src/components/PopupInstance.svelte
index 524dfc562b..83c50607c7 100644
--- a/packages/ui/src/components/PopupInstance.svelte
+++ b/packages/ui/src/components/PopupInstance.svelte
@@ -83,7 +83,9 @@
       options.props.maxHeight = '100vh'
       if (!modalHTML.classList.contains('fullsize')) modalHTML.classList.add('fullsize')
     } else {
-      options = fitPopupElement(modalHTML, device, element, contentPanel, clientWidth, clientHeight)
+      if (element !== 'float' || options?.props?.top === undefined || options?.props?.top === '') {
+        options = fitPopupElement(modalHTML, device, element, contentPanel, clientWidth, clientHeight)
+      }
       if (modalHTML.classList.contains('fullsize')) modalHTML.classList.remove('fullsize')
     }
     options.fullSize = fullSize
@@ -126,6 +128,16 @@
     )
   }
 
+  let drag: boolean = false
+
+  const dragParams: {
+    x: number
+    y: number
+  } = {
+    x: 0,
+    y: 0
+  }
+
   export function fitPopupInstance (): void {
     if (modalHTML) {
       fitPopup(modalHTML, element, contentPanel)
@@ -148,7 +160,7 @@
 <div
   class="popup {testing ? 'endShow' : showing === undefined ? 'endShow' : !showing ? 'preShow' : 'startShow'}"
   class:testing
-  class:anim={(element === 'float' || element === 'centered') && !testing}
+  class:anim={(element === 'float' || element === 'centered') && !testing && !drag}
   bind:this={modalHTML}
   style={`z-index: ${zIndex + 1};`}
   style:top={options?.props?.top}
@@ -167,6 +179,22 @@
     clientHeight = element.clientHeight
     fitPopupInstance()
   }}
+  on:mousedown={(e) => {
+    if (element === 'float') {
+      dragParams.x = e.offsetX
+      dragParams.y = e.offsetY
+      drag = true
+    }
+  }}
+  on:mouseup={() => {
+    drag = false
+  }}
+  on:mousemove={(e) => {
+    if (element === 'float' && drag) {
+      options.props.top = `${e.clientY - dragParams.y}px`
+      options.props.left = `${e.clientX - dragParams.x}px`
+    }
+  }}
 >
   <svelte:component
     this={is}
@@ -189,15 +217,24 @@
   />
 </div>
 
-{#if overlay}
+{#if overlay || drag}
   <!-- svelte-ignore a11y-no-static-element-interactions -->
   <div
     class="modal-overlay"
     class:testing
-    class:antiOverlay={options?.showOverlay}
+    class:antiOverlay={options?.showOverlay && !drag}
     style={`z-index: ${zIndex};`}
     on:click={handleOverlayClick}
     on:keydown|stopPropagation|preventDefault={() => {}}
+    on:mouseup={() => {
+      drag = false
+    }}
+    on:mousemove={(e) => {
+      if (element === 'float' && drag) {
+        options.props.top = `${e.clientY - dragParams.y}px`
+        options.props.left = `${e.clientX - dragParams.x}px`
+      }
+    }}
   />
 {/if}
 
diff --git a/packages/ui/src/popups.ts b/packages/ui/src/popups.ts
index 279b40e6c4..227c8c383d 100644
--- a/packages/ui/src/popups.ts
+++ b/packages/ui/src/popups.ts
@@ -228,10 +228,14 @@ export function fitPopupElement (
       newProps.maxHeight = fullHeight ? 'calc(100vh - 2rem)' : '75vh'
       show = true
     } else if (element === 'float') {
-      newProps.top = 'calc(var(--status-bar-height) + 4px)'
-      newProps.bottom = '4px'
-      newProps.left = '60%'
-      newProps.right = '4px'
+      if (clientWidth !== undefined && clientHeight !== undefined) {
+        newProps.top = `calc(50% - ${clientHeight / 2}px`
+        newProps.left = `calc(50% - ${clientWidth / 2}px`
+      } else {
+        newProps.top = '50%'
+        newProps.left = '50%'
+        newProps.transform = 'translate(-50%, -50%)'
+      }
       show = true
     } else if (element === 'center') {
       if (clientWidth !== undefined && clientHeight !== undefined) {