diff --git a/app/components/viewer/document/index.hbs b/app/components/viewer/document/index.hbs
index b887ef330f66a0a6e64ddfd235a746d636b35c6c..3f6e66c0134b5ce718eee2b74c687f60aa53b8d7 100644
--- a/app/components/viewer/document/index.hbs
+++ b/app/components/viewer/document/index.hbs
@@ -7,6 +7,8 @@
       @onDblClick={{this.onThumbnailDblClick}}
       @onCheckboxChange={{@onCheckboxChange}}
       @onThumbnailsPositionChanged={{@onThumbnailsPositionChanged}}
+      @onAddThumbnailPlaceholderAt={{@onAddThumbnailPlaceholderAt}}
+      @onRemoveThumbnailPlaceholder={{@onRemoveThumbnailPlaceholder}}
       @onIncomingPages={{@onIncomingPages}} />
   {{/if}}
   <Viewer::ThumbnailsSwitch
diff --git a/app/components/viewer/index.hbs b/app/components/viewer/index.hbs
index 693d352c88fd8c9e992c00f7586886d9620790cd..1925961bb7d809f71d10d11cc373c90fb5b96709 100644
--- a/app/components/viewer/index.hbs
+++ b/app/components/viewer/index.hbs
@@ -53,5 +53,7 @@
     @thumbnails_visible={{this.thumbnails_visible}}
     @onCheckboxChange={{this.onThumbnailCheckboxChange}}
     @onThumbnailsPositionChanged={{this.onThumbnailsPositionChanged}}
+    @onAddThumbnailPlaceholderAt={{this.onAddThumbnailPlaceholderAt}}
+    @onRemoveThumbnailPlaceholder={{this.onRemoveThumbnailPlaceholder}}
     @onIncomingPages={{this.onIncomingPages}} />
 </div>
diff --git a/app/components/viewer/index.js b/app/components/viewer/index.js
index 4066871d8382112a82c93c3b0c3dd3ab2eed459f..6289865215a07fc85356c3e3944f625f3fd8e473 100644
--- a/app/components/viewer/index.js
+++ b/app/components/viewer/index.js
@@ -5,7 +5,6 @@ import { action } from '@ember/object';
 import { A } from '@ember/array';
 import {
   reposition_items,
-  get_id,
   detect_order_changes
 } from 'papermerge/utils/array';
 
@@ -163,6 +162,34 @@ export default class ViewerComponent extends Component {
     });
   }
 
+  @action
+  onAddThumbnailPlaceholderAt(pos) {
+    let new_pages,
+      placeholder;
+
+    new_pages = Array.from(this.pages);
+    placeholder = {'is_placeholder': true};
+    if (!new_pages.find(item => item.is_placeholder)) {
+      // Only one placeholder is allowed
+      new_pages.splice(pos, 0, placeholder);
+      this.pages = new_pages;
+    }
+  }
+
+  @action
+  onRemoveThumbnailPlaceholder() {
+    let new_pages,
+      placeholder_pos;
+
+    new_pages = Array.from(this.pages);
+    placeholder_pos = new_pages.findIndex(item => item.is_placeholder);
+    if (placeholder_pos >= 0) {
+      console.log(`placeholder found at pos ${placeholder_pos}`)
+      new_pages.splice(placeholder_pos, 1);
+      this.pages = new_pages;
+    }
+  }
+
   @action
   async onIncomingPages({page_ids, drop_pos}) {
     await this.requests.moveToDocument({
diff --git a/app/components/viewer/thumbnails/index.hbs b/app/components/viewer/thumbnails/index.hbs
index a5d37e3691be78985db3202833a9cc667093367a..75524ad3cc1d787c563f03dd95110387e96ac1f2 100644
--- a/app/components/viewer/thumbnails/index.hbs
+++ b/app/components/viewer/thumbnails/index.hbs
@@ -8,13 +8,17 @@
 
   {{adjust_element_height}}>
   {{#each @pages as |page|}}
-    <Viewer::Thumbnail
-      @doc={{@doc}}
-      @page={{page}}
-      @selectedPages={{@selectedPages}}
-      @onDblClick={{@onDblClick}}
-      @onDragendSuccess={{this.onDragendSuccess}}
-      @onDragendCancel={{this.onDragendCancel}}
-      @onCheckboxChange={{@onCheckboxChange}} />
+    {{#if page.is_placeholder}}
+      Placeholder
+    {{else}}
+      <Viewer::Thumbnail
+        @doc={{@doc}}
+        @page={{page}}
+        @selectedPages={{@selectedPages}}
+        @onDblClick={{@onDblClick}}
+        @onDragendSuccess={{this.onDragendSuccess}}
+        @onDragendCancel={{this.onDragendCancel}}
+        @onCheckboxChange={{@onCheckboxChange}} />
+    {{/if}}
   {{/each}}
 </div>
diff --git a/app/components/viewer/thumbnails/index.js b/app/components/viewer/thumbnails/index.js
index 10729f555557f7e762031990469546d098ac3836..8befac90f1e7a6170787336f291ff6701d1668db 100644
--- a/app/components/viewer/thumbnails/index.js
+++ b/app/components/viewer/thumbnails/index.js
@@ -54,7 +54,57 @@ export default class ViewerThumbnailsComponent extends Component {
   }
 
   @action
-  onDragOver() {
+  onDragOver({event, element}) {
+    /*
+    Creates DOM placeholder suggesting to user that here he/she can drop the page.
+
+    Only one placeholder DOM element is allowed.
+    */
+    let thumbnail_dom_items,
+      cursor_coord,
+      pos,
+      rect,
+      cursor_before_child = 0,
+      outside_all_thumbnails = true,
+      svg_element;
+
+    if (!element) {
+      return;
+    }
+
+    cursor_coord = new Point(event.clientX, event.clientY);
+    thumbnail_dom_items = Array.from(element.children);
+
+    thumbnail_dom_items.forEach(thumbnail_dom_item => {
+      // page_item is DOM element which may be real thumbnail of the page or
+      // it may be a paceholder used as suggestion that it is OK to drop page here.
+      // Real page thumbnail DOM element contains DOM element for image/svg
+      // and DOM element denoting page number
+      svg_element = thumbnail_dom_item.querySelector('svg');
+      if (svg_element) { // in case of thumbnail placeholder, there won't be SVG element
+        rect = svg_element.getBoundingClientRect();
+
+        if (cursor_coord.y <= rect.y) {
+          cursor_before_child += 1;
+        }
+        // Check if cursor position is outside of any thumbnail i.e.
+        // position to drop will be suggested only in case cursor coordinate
+        // is BETWEEN thumbnails images/svg
+        if ((cursor_coord.y < rect.bottom) && (cursor_coord.y > rect.top)) {
+          outside_all_thumbnails = false;
+        }
+      }
+    });
+
+    // position where to suggest page drop
+    pos = thumbnail_dom_items.length - cursor_before_child;
+
+    if (outside_all_thumbnails) {
+      // suggest position to drop ONLY of cursor is outside of all thumbnails
+      this.args.onAddThumbnailPlaceholderAt(pos);
+    } else {
+      this.args.onRemoveThumbnailPlaceholder();
+    }
   }
 
   @action
diff --git a/app/modifiers/droppable.js b/app/modifiers/droppable.js
index 32577290db2a8629905ccc29484334badf75c5c6..1822f8b6019aa21ad8619c2ed3cc6b38ec0015fb 100644
--- a/app/modifiers/droppable.js
+++ b/app/modifiers/droppable.js
@@ -38,11 +38,17 @@ export default class DrappableModifier extends Modifier {
 
   @action
   onDragOver(event) {
-    const isNode = event.dataTransfer.types.includes("application/x.node");
+    //const isNode = event.dataTransfer.types.includes("application/x.node");
 
-    event.preventDefault();
-    if (isNode) {
+    //event.preventDefault();
+    //if (isNode) {
       //console.log(`dragging over a node`);
+    //}
+    let _onDragOver = this.args.named['onDragOver'], element;
+
+    element = this.element;
+    if (_onDragOver) {
+      _onDragOver({event, element});
     }
   }
 
diff --git a/app/utils/array.js b/app/utils/array.js
index 46b92d115b0f28062144cc5258b20781ff5fac73..67bcecce12294ed515cc4c6aac77b6f5f70bc38a 100644
--- a/app/utils/array.js
+++ b/app/utils/array.js
@@ -124,7 +124,7 @@ function detect_order_changes(arr1, arr2) {
   }
 
   if (arr1.length != arr2.length) {
-    throw 'Invalid input. Both arrays need to be of same length';
+    return false;
   }
 
   arr1.forEach((item, index) => {