diff --git a/app/controllers/start.php b/app/controllers/start.php
index f47520297c16a46ba98d15962fce31dae5cad089..e48bc899a25b10af9381069004c544542743c55a 100644
--- a/app/controllers/start.php
+++ b/app/controllers/start.php
@@ -255,16 +255,17 @@ class StartController extends AuthenticatedController
 
     /**
      *  Action to store the widget placements
-     *
-     * @return void
      */
-    public function storeNewOrder_action()
+    public function storeNewOrder_action(): void
     {
-        WidgetHelper::storeNewPositions(
-            Request::get('widget'),
-            Request::get('position'),
-            Request::get('column')
-        );
+        if (!Request::isPost()) {
+            throw new MethodNotAllowedException();
+        }
+
+        $lanes = Request::getArray('lanes');
+
+        WidgetHelper::storeNewPositions($lanes);
+
         $this->render_nothing();
     }
 
diff --git a/lib/classes/WidgetHelper.php b/lib/classes/WidgetHelper.php
index 2122a60c763c1a33489e7303c02de8b51a23eb98..548184ebb6b83968827f5ba0b4ec2e71a81d13ec 100644
--- a/lib/classes/WidgetHelper.php
+++ b/lib/classes/WidgetHelper.php
@@ -63,37 +63,48 @@ class WidgetHelper
     /**
      * storeNewPositions - stores new Widget positions for a given user
      *
-     * @param array ids of widgets to be stored
+     * @param array $lanes array with column as index and ids array as value
      *
      * @return void
      */
-    public static function storeNewPositions($widget, $position, $column)
+    public static function storeNewPositions(array $lanes): void
     {
-        $db = DBManager::get();
-        $oldWidget = $db->fetchOne("SELECT position,col FROM widget_user WHERE id = ? AND range_id = ?", [$widget, $GLOBALS['user']->id]);
-        if ($oldWidget) {
-
-            if ($oldWidget['col'] == $column) {
-                // Insert element
-                $db->execute("UPDATE widget_user SET position = ? WHERE id = ? ", [$position, $widget]);
-                if ($oldWidget['position'] < $position) {
-                    //Move back items BETWEEN old and new position
-                    $db->execute("UPDATE widget_user SET position = position - 1 WHERE col = ? AND range_id = ? AND position > ? AND  position <= ? AND id <> ?", [$oldWidget['col'], $GLOBALS['user']->id, $oldWidget['position'], $position, $widget]);
-                } else {
-                    //Move forward items BETWEEN old and new position
-                    $db->execute("UPDATE widget_user SET position = position + 1 WHERE col = ? AND range_id = ? AND position < ? AND  position >= ? AND id <> ?", [$oldWidget['col'], $GLOBALS['user']->id, $oldWidget['position'], $position, $widget]);
-                }
-            } else {
-                // Push all entries in the new column one position away
-                $db->execute("UPDATE widget_user SET position = position + 1 WHERE range_id = ? AND col = ? AND position >= ?", [$GLOBALS['user']->id, $column, $position]);
+        // Query not displayed widgets to sort them to the bottom of a lane
+        $query = "SELECT `col`, `id`
+                  FROM `widget_user`
+                  WHERE `range_id` = ?
+                    AND `id` NOT IN (?)
+                  ORDER BY `col`, `position`";
+        $undisplayed = DBManager::get()->fetchGrouped($query, [
+            User::findCurrent()->id,
+            array_merge(...$lanes)
+        ], function ($row) {
+            return array_column($row, 'id');
+        });
+
+        // Set new positions
+        $query = "UPDATE `widget_user`
+                  SET `col` = :column,
+                      `position` = :position
+                  WHERE `id` = :id
+                    AND `range_id` = :user_id";
+        $statement = DBManager::get()->prepare($query);
+        $statement->bindValue(':user_id', User::findCurrent()->id);
 
-                // Insert element
-                $db->execute("UPDATE widget_user SET position = ?, col = ? WHERE id = ? ", [$position, $column, $widget]);
+        foreach ([0, 1] as $column) {
+            $statement->bindValue(':column', $column);
 
-                // Move positions in old column
-                $db->execute("UPDATE widget_user SET position = position - 1 WHERE col = ? AND range_id = ? AND position > ?", [$oldWidget['col'], $GLOBALS['user']->id, $oldWidget['position']]);
-            }
+            $ids = array_merge(
+                $lanes[$column] ?? [],
+                $undisplayed[$column] ?? []
+            );
 
+            $position = 0;
+            foreach ($ids as $id) {
+                $statement->bindValue(':position', $position++);
+                $statement->bindValue(':id', $id);
+                $statement->execute();
+            }
         }
     }
 
diff --git a/resources/assets/javascripts/lib/startpage.js b/resources/assets/javascripts/lib/startpage.js
index 15b2c591acea40aa13417ccc901dcc6cf7513cbb..1d7de31fa82871afc6757f7a63cd7048df783e1b 100644
--- a/resources/assets/javascripts/lib/startpage.js
+++ b/resources/assets/javascripts/lib/startpage.js
@@ -1,22 +1,31 @@
 const startpage = {
-    init: function() {
+    init() {
         $('.start-widgetcontainer .portal-widget-list').sortable({
             handle: '.widget-header',
             connectWith: 'ul.portal-widget-list',
-            start: function() {
+            start() {
                 $(this)
                     .closest('.start-widgetcontainer')
                     .find('.portal-widget-list')
-                    .addClass('ui-sortable move');
+                    .addClass('move');
             },
-            stop: function(event, ui) {
-                $.get(STUDIP.ABSOLUTE_URI_STUDIP + 'dispatch.php/start/storeNewOrder', {
-                    widget: $(ui.item).attr('id'),
-                    position: $(ui.item).index(),
-                    column: $(ui.item)
-                        .parent()
-                        .index()
-                });
+            update(event, ui) {
+                let lanes = [];
+                $(this)
+                    .closest('.start-widgetcontainer')
+                    .children('.portal-widget-list')
+                    .each((index, element) => {
+                        lanes[index] = $('.studip-widget-wrapper', element)
+                            .map((i, el) => el.getAttribute('id'))
+                            .get(); // Ensure we have an array
+                    });
+
+                $.post(
+                    STUDIP.URLHelper.getURL('dispatch.php/start/storeNewOrder'),
+                    {lanes}
+                );
+            },
+            stop() {
                 $(this)
                     .closest('.start-widgetcontainer')
                     .find('.portal-widget-list')
@@ -25,7 +34,7 @@ const startpage = {
         });
     },
 
-    init_edit: function(perm) {
+    init_edit(perm) {
         $('.edit-widgetcontainer .portal-widget-list').sortable({
             handle: '.widget-header',
             connectWith: '.edit-widgetcontainer .portal-widget-list',