diff --git a/wgp.py b/wgp.py
index 95ee8cd..a8f288d 100644
--- a/wgp.py
+++ b/wgp.py
@@ -888,6 +888,29 @@ def update_task_thumbnails(task,  inputs):
         "end_image_data_base64": [pil_to_base64_uri(img, format="jpeg", quality=70) for img in end_image_data] if end_image_data != None else None
     })
 
+def move_task(queue, old_index_str, new_index_str):
+    try:
+        old_idx = int(old_index_str)
+        new_idx = int(new_index_str)
+    except (ValueError, IndexError):
+        return update_queue_data(queue)
+
+    with lock:
+        old_idx += 1
+        new_idx += 1
+
+        if not (0 < old_idx < len(queue)):
+            return update_queue_data(queue)
+
+        item_to_move = queue.pop(old_idx)
+        if old_idx < new_idx:
+            new_idx -= 1
+        clamped_new_idx = max(1, min(new_idx, len(queue)))
+        
+        queue.insert(clamped_new_idx, item_to_move)
+
+    return update_queue_data(queue)
+
 def move_up(queue, selected_indices):
     if not selected_indices or len(selected_indices) == 0:
         return update_queue_data(queue)
@@ -1462,14 +1485,13 @@ def generate_queue_html(queue):
     
         
             
+                | Drag | 
                 Qty | 
                 Prompt | 
                 Length | 
                 Steps | 
                 Start/Ref | 
                 End | 
-                 | 
-                 | 
                  | 
                  | 
             
@@ -1505,22 +1527,20 @@ def generate_queue_html(queue):
         end_img_md = ""
         if end_img_uri:
             end_img_md = f''
-        
-        up_btn = f""""""
-        down_btn = f""""""
+
+        drag_handle = f'☰ | '
         edit_btn = f""""""
         remove_btn = f""""""
 
         row_html = f"""
-        
+        
+            {drag_handle}
             | {item.get('repeats', "1")} | 
             {prompt_cell} | 
             {length} | 
             {num_steps} | 
             {start_img_md} | 
             {end_img_md} | 
-            {up_btn} | 
-            {down_btn} | 
             {edit_btn} | 
             {remove_btn} | 
         
@@ -6954,12 +6974,14 @@ def handle_queue_action(state, action_string):
     queue = gen.get("queue", [])
     
     try:
-        action, row_index_str = action_string.split('_')
-        row_index = int(row_index_str)
+        parts = action_string.split('_')
+        action = parts[0]
+        params = parts[1:]
     except (IndexError, ValueError):
         return gr.HTML(), gr.Tabs()
 
     if action == "edit":
+        row_index = int(params[0])
         state["editing_task_index"] = row_index
         task_to_edit_index = row_index + 1
         
@@ -6971,11 +6993,12 @@ def handle_queue_action(state, action_string):
             gr.Warning("Task index out of bounds.")
             return update_queue_data(queue), gr.Tabs()
             
-    elif action == "up":
-        return move_up(queue, [row_index]), gr.Tabs()
-    elif action == "down":
-        return move_down(queue, [row_index]), gr.Tabs()
+    elif action == "move" and len(params) == 3 and params[1] == "to":
+        old_index_str, new_index_str = params[0], params[2]
+        return move_task(queue, old_index_str, new_index_str), gr.Tabs()
+        
     elif action == "remove":
+        row_index = int(params[0])
         new_queue_data = remove_task(queue, [row_index])
         gen["prompts_max"] = gen.get("prompts_max", 0) - 1
         update_status(state)
@@ -9582,6 +9605,20 @@ def create_ui():
             display: block;
             margin: auto;
         }
+        #queue_html_container .drag-handle {
+            cursor: grab;
+            user-select: none;
+        }
+        #queue_html_container tr.dragging {
+            opacity: 0.5;
+            background: #2d3748;
+        }
+        #queue_html_container tr.drag-over-top {
+            border-top: 2px solid #4299e1;
+        }
+        #queue_html_container tr.drag-over-bottom {
+            border-bottom: 2px solid #4299e1;
+        }
         #image-modal-container {
             position: fixed;
             top: 0;
@@ -9771,6 +9808,116 @@ def create_ui():
             }
         };
 
+        let draggedItem = null;
+
+        function initializeQueueDragAndDrop() {
+            const queueTbody = document.querySelector('#queue_html_container table > tbody');
+            if (!queueTbody || queueTbody.dataset.dndInitialized) {
+                return;
+            }
+            
+            queueTbody.dataset.dndInitialized = 'true';
+
+            queueTbody.addEventListener('dragstart', (e) => {
+                if (e.target.classList.contains('drag-handle')) {
+                    draggedItem = e.target.closest('.draggable-row');
+                    if (draggedItem) {
+                        setTimeout(() => {
+                            draggedItem.classList.add('dragging');
+                        }, 0);
+                    }
+                }
+            });
+
+            queueTbody.addEventListener('dragend', (e) => {
+                if (draggedItem) {
+                    draggedItem.classList.remove('dragging');
+                    draggedItem = null;
+                    document.querySelectorAll('.drag-over-top, .drag-over-bottom').forEach(el => {
+                        el.classList.remove('drag-over-top', 'drag-over-bottom');
+                    });
+                }
+            });
+
+            queueTbody.addEventListener('dragover', (e) => {
+                e.preventDefault();
+                const targetRow = e.target.closest('.draggable-row');
+                
+                // Clear previous indicators
+                document.querySelectorAll('.drag-over-top, .drag-over-bottom').forEach(el => {
+                    el.classList.remove('drag-over-top', 'drag-over-bottom');
+                });
+
+                if (targetRow && draggedItem && targetRow !== draggedItem) {
+                    const rect = targetRow.getBoundingClientRect();
+                    const midpoint = rect.top + rect.height / 2;
+                    
+                    if (e.clientY < midpoint) {
+                        targetRow.classList.add('drag-over-top');
+                    } else {
+                        targetRow.classList.add('drag-over-bottom');
+                    }
+                }
+            });
+
+            queueTbody.addEventListener('dragleave', (e) => {
+                 const relatedTarget = e.relatedTarget;
+                 const queueTable = e.currentTarget.closest('table');
+                 if (queueTable && !queueTable.contains(relatedTarget)) {
+                    document.querySelectorAll('.drag-over-top, .drag-over-bottom').forEach(el => {
+                        el.classList.remove('drag-over-top', 'drag-over-bottom');
+                    });
+                 }
+            });
+
+            queueTbody.addEventListener('drop', (e) => {
+                e.preventDefault();
+                const targetRow = e.target.closest('.draggable-row');
+
+                if (draggedItem && targetRow && targetRow !== draggedItem) {
+                    const oldIndex = draggedItem.dataset.index;
+                    let newIndex = parseInt(targetRow.dataset.index);
+
+                    // If dropping on the bottom half, the new index is after the target row
+                    if (targetRow.classList.contains('drag-over-bottom')) {
+                        newIndex++;
+                    }
+
+                    if (oldIndex != newIndex) {
+                       const action = `move_${oldIndex}_to_${newIndex}`;
+                       window.updateAndTrigger(action);
+                    }
+                }
+
+                // Cleanup visual styles
+                document.querySelectorAll('.drag-over-top, .drag-over-bottom').forEach(el => {
+                    el.classList.remove('drag-over-top', 'drag-over-bottom');
+                });
+                if (draggedItem) {
+                    draggedItem.classList.remove('dragging');
+                    draggedItem = null;
+                }
+            });
+        }
+        
+        const observer = new MutationObserver((mutationsList, observer) => {
+            for(const mutation of mutationsList) {
+                if (mutation.type === 'childList') {
+                    const queueContainer = document.querySelector('#queue_html_container');
+                    if (queueContainer && queueContainer.querySelector('table > tbody')) {
+                        initializeQueueDragAndDrop();
+                    }
+                }
+            }
+        });
+
+        const targetNode = document.querySelector('gradio-app');
+        if (targetNode) {
+            observer.observe(targetNode, { childList: true, subtree: true });
+        }
+        
+        setTimeout(initializeQueueDragAndDrop, 500);
+
         // cancel wheel usage inside image editor    
         const hit = n => n?.id === "img_editor" || n?.classList?.contains("wheel-pass");
         addEventListener("wheel", e => {