diff --git a/form_builder.css b/form_builder.css
index 7101d30..f739071 100644
--- a/form_builder.css
+++ b/form_builder.css
@@ -15,6 +15,7 @@
   margin-right: 270px;
   padding-right: 9px;
   border-right: 1px solid #CCC;
+  position: relative;
 }
 
 #center #form-builder form,
@@ -108,11 +109,11 @@ div.form-builder-title-bar {
   border-bottom: none;
 }
 
-div.ui-sortable div.form-builder-title-bar {
+div.ui-draggable div.form-builder-title-bar {
   display: none;
 }
 
-div.ui-sortable div.form-builder-title-bar {
+div.ui-draggable div.form-builder-title-bar {
   cursor: move;
 }
 
@@ -122,13 +123,13 @@ span.form-builder-links {
   z-index: 40;
 }
 
-div.form-builder-hover div.form-builder-title-bar,
-div.form-builder-active div.form-builder-title-bar {
+div.form-builder-hover > div.form-builder-title-bar,
+div.form-builder-active > div.form-builder-title-bar {
   display: block;
 }
 
-div.ui-sortable div.form-builder-hover div.form-builder-wrapper div.form-builder-title-bar,
-div.ui-sortable div.form-builder-active div.form-builder-wrapper div.form-builder-title-bar {
+div.ui-draggable div.form-builder-hover div.form-builder-wrapper div.form-builder-title-bar,
+div.ui-draggable div.form-builder-active div.form-builder-wrapper div.form-builder-title-bar {
   display: none;
 }
 
@@ -320,3 +321,18 @@ div.form-builder-new-field span.progress {
   background-image: url(images/fields/title.png);
 }
 
+.form-builder-placeholder {
+  height: 60px;
+  margin-top: -30px;
+  position: absolute;
+  width: 100%;
+}
+
+.form-builder-placeholder.over {
+  margin: 0;
+  position: relative;
+}
+
+.form-builder-wrapper.ui-draggable-dragging {
+  width: 100%;
+}
diff --git a/form_builder.js b/form_builder.js
index 86ea4bc..ce1ac54 100644
--- a/form_builder.js
+++ b/form_builder.js
@@ -74,22 +74,21 @@ Drupal.behaviors.formBuilderFields.attach = function(context) {
  */
 Drupal.behaviors.formBuilder = {};
 Drupal.behaviors.formBuilder.attach = function(context) {
-  var formbuilder = $('#form-builder', context);
-  formbuilder.sortable({
-    items: 'div.form-builder-wrapper',
+  var formbuilder = $('#form-builder');
+  var elements = $('.form-builder-wrapper').not('.form-builder-empty-placeholder').not('.ui-draggable');
+  elements.draggable({
+    distance: 4, // Pixels before dragging starts.
     handle: 'div.form-builder-title-bar, div.form-builder-element',
-    axis: 'y',
+    helper: 'clone',
     opacity: 0.8,
-    forcePlaceholderSize: true,
+    revert: true,
+    revertDuration: 0,
+    scope: 'form-builder',
     scroll: true,
     scrollSensitivity: 50,
-    distance: 4, // Pixels before dragging starts.
-    appendTo: 'body',
-    helper: createHelper,
-    sort: Drupal.formBuilder.elementIndent, // Called on drag.
+    zIndex: 100,
     start: Drupal.formBuilder.startDrag,
-    stop: Drupal.formBuilder.stopDrag,
-    change: Drupal.formBuilder.checkFieldsets
+    stop: Drupal.formBuilder.stopDrag
   });
 
   // This sets the height of the drag target to be at least as hight as the field
@@ -99,11 +98,6 @@ Drupal.behaviors.formBuilder.attach = function(context) {
   // here.
   var property = $.browser.msie && $.browser.version < 7 ? 'height' : 'min-height';
   formbuilder.css(property, $('#form-builder-fields').height());
-
-  // This helper function is needed to make the appendTo option take effect.
-  function createHelper(e, $el) {
-    return $el.clone().get(0);
-  }
 };
 
 /**
@@ -167,8 +161,8 @@ Drupal.behaviors.formBuilderDeleteConfirmation.attach = function(context) {
 Drupal.behaviors.formBuilderMousePress = {};
 Drupal.behaviors.formBuilderMousePress.attach = function(context) {
   if (context == document) {
-    $('body').mousedown(function() { Drupal.formBuilder.mousePressed = 1; });
-    $('body').mouseup(function() { Drupal.formBuilder.mousePressed = 0; });
+    $('body').mousedown(function() {Drupal.formBuilder.mousePressed = 1;});
+    $('body').mouseup(function() {Drupal.formBuilder.mousePressed = 0;});
   }
 };
 
@@ -195,10 +189,10 @@ Drupal.behaviors.formBuilderBlockScroll.attach = function(context) {
       if (windowOffset - blockScrollStart > 0) {
         // Do not scroll beyond the bottom of the editing area.
         var newTop = Math.min(windowOffset - blockScrollStart + 20, formBuilderHeight - blockHeight);
-        $block.animate({ top: (newTop + 'px') }, 'fast');
+        $block.animate({top: (newTop + 'px')}, 'fast');
       }
       else {
-        $block.animate({ top: '0px' }, 'fast');
+        $block.animate({top: '0px'}, 'fast');
       }
     }
 
@@ -227,13 +221,14 @@ Drupal.behaviors.formBuilderNewField.attach = function(context) {
     $list.children('li:not(.ui-draggable)').draggable({
       opacity: 0.8,
       helper: 'clone',
+      scope: 'form-builder',
       scroll: true,
       scrollSensitivity: 50,
-      containment: 'body',
-      connectToSortable: '#form-builder',
-      start: Drupal.formBuilder.startPaletteDrag,
-      stop: Drupal.formBuilder.stopPaletteDrag,
-      change: Drupal.formBuilder.checkFieldsets
+      stack: '.form-builder-wrapper',
+      tolerance: 'pointer',
+      zIndex: 100,
+      start: Drupal.formBuilder.startDrag,
+      stop: Drupal.formBuilder.stopDrag
     });
   }
 };
@@ -349,14 +344,14 @@ Drupal.formBuilder.editField = function() {
  * Click handler for deleting a field.
  */
 Drupal.formBuilder.deleteField = function() {
-  $(this).parents('div.form-builder-wrapper:first').animate({ height: 'hide', opacity: 'hide' }, 'normal', function() {
+  $(this).parents('div.form-builder-wrapper:first').animate({height: 'hide', opacity: 'hide'}, 'normal', function() {
     // If this is a unique field, show the field in the palette again.
     var elementId = $(this).find('div.form-builder-element').attr('id');
     $('ul.form-builder-fields').find('li.' + elementId).show('slow');
+    // Check for empty fieldsets.
+    Drupal.formBuilder.checkFieldsets([this]);
     // Remove the field from the form.
     $(this).remove();
-    // Check for empty fieldsets.
-    Drupal.formBuilder.checkFieldsets(null, null, true);
   });
 };
 
@@ -550,21 +545,63 @@ Drupal.formBuilder.updateElementPosition = function(element) {
  */
 Drupal.formBuilder.startDrag = function(e, ui) {
   Drupal.formBuilder.activeDragUi = ui;
+
+  var $this = $(this);
+  if ($this.hasClass('form-builder-unique') || $this.hasClass('form-builder-wrapper')) {
+    $this.hide();
+  }
+
+  // Check fieldsets and add placeholder text if needed
+  Drupal.formBuilder.checkFieldsets([this, ui.helper]);
+
+  // Create the drop targets in between the form elements
+  Drupal.formBuilder.createDropTargets(this);
 };
 
 /**
- * Called when a field has been moved via Sortables.
- *
- * @param e
- *   The event object containing status information about the event.
- * @param ui
- *   The jQuery Sortables object containing information about the sortable.
+ * Creates drop targets for the dragged element to be dropped into.
  */
-Drupal.formBuilder.stopDrag = function(e, ui) {
-  var $element = ui.item;
+Drupal.formBuilder.createDropTargets = function(draggable) {
+  var $placeholder = $('<div class="form-builder-placeholder"></div>');
+  var $elements = $('#form-builder .form-builder-wrapper:not(.form-builder-empty-placeholder)').not(draggable);
+  
+  if ($elements.length == 0) {
+    // There are no form elements, insert a placeholder
+    var $formBuilder = $('#form-builder');
+    $placeholder.height($formBuilder.height());
+    $placeholder.appendTo($formBuilder);
+  } else {
+    $elements.each(function(i, element) {
+      $placeholder.clone().insertAfter(this);
+      // If the element is the first in its container, add a drop target above it.
+      if (element == $(element).parent().children('.form-builder-wrapper')[0]) {
+        $placeholder.clone().insertBefore(this);
+      }
+    });
+  }
+  
+  // Enable the drop targets
+  $('#form-builder').find('.form-builder-placeholder, .form-builder-empty-placeholder').droppable({
+    greedy: true,
+    hoverClass: 'over',
+    scope: 'form-builder',
+    tolerance: 'pointer',
+    drop: Drupal.formBuilder.dropElement,
+    over: Drupal.formBuilder.dropHover,
+    out: Drupal.formBuilder.dropHover
+  });
+};
 
+/**
+ * Handles form elements being dropped onto the form.  Existing elements will
+ * trigger a reorder, while new elements will be added in place to the form.
+ */
+Drupal.formBuilder.dropElement = function (event, ui) {
+  var $element = ui.draggable;
+  var $placeholder = $(this);
+  
   // If the element is a new field from the palette, update it with a real field.
-  if ($element.is('.ui-draggable')) {
+  if ($element.is('#form-builder-field-palette .ui-draggable')) {
     var name = 'new_' + new Date().getTime();
     // If this is a "unique" element, its element ID is hard-coded.
     if ($element.is('.form-builder-unique')) {
@@ -572,7 +609,7 @@ Drupal.formBuilder.stopDrag = function(e, ui) {
     }
 
     var $ajaxPlaceholder = $('<div class="form-builder-wrapper form-builder-new-field"><div id="form-builder-element-' + name + '" class="form-builder-element"><span class="progress">' + Drupal.t('Please wait...') + '</span></div></div>');
-
+  
     $.ajax({
       url: $element.find('a').attr('href'),
       type: 'GET',
@@ -581,12 +618,15 @@ Drupal.formBuilder.stopDrag = function(e, ui) {
       success: Drupal.formBuilder.addElement
     });
 
-    $element.replaceWith($ajaxPlaceholder);
+    $placeholder.replaceWith($ajaxPlaceholder);
 
     Drupal.formBuilder.updatingElement = true;
   }
   // Update the positions (weights and parents) in the form cache.
   else {
+    $element.removeAttr('style');
+    $placeholder.replaceWith($element);
+    ui.helper.remove();
     Drupal.formBuilder.updateElementPosition($element.get(0));
   }
 
@@ -597,77 +637,41 @@ Drupal.formBuilder.stopDrag = function(e, ui) {
 };
 
 /**
- * Called when a field is about to be moved from the new field palette.
- *
- * @param e
- *   The event object containing status information about the event.
- * @param ui
- *   The jQuery Sortables object containing information about the sortable.
+ * This handles adjusting the placeholder height for drop targets when the 
+ * dragged item is held above them.
  */
-Drupal.formBuilder.startPaletteDrag = function(e, ui) {
-  var $this = $(this);
-  if ($this.is('.form-builder-unique')) {
-    $this.css('visibility', 'hidden');
+Drupal.formBuilder.dropHover = function (event, ui) {
+  if (event.type == 'mouseenter') {
+    $(this).height(ui.helper.height());
+  } else {
+    $(this).removeAttr('style');
   }
-
-  Drupal.formBuilder.activeDragUi = ui;
 };
 
 /**
- * Called after a field has been moved from the new field palette.
+ * Called when a field has stopped moving via draggable.
  *
  * @param e
  *   The event object containing status information about the event.
  * @param ui
  *   The jQuery Sortables object containing information about the sortable.
  */
-Drupal.formBuilder.stopPaletteDrag = function(e, ui) {
+Drupal.formBuilder.stopDrag = function(e, ui) {
   var $this = $(this);
-  // If the activeDragUi is still set, we did not drop onto the form.
   if (Drupal.formBuilder.activeDragUi) {
-    ui.helper.remove();
-    Drupal.formBuilder.activeDragUi = false;
-    $this.css('visibility', '');
-    $(window).scroll();
-  }
-  // If dropped onto the form and a unique field, remove it from the palette.
-  else if ($this.is('.form-builder-unique')) {
-    $this.animate({ height: '0', width: '0' }, function() {
-      $this.css({ visibility: '', height: '', width: '', display: 'none' });
-    });
-  }
-};
-
-/**
- * Update the indentation and width of elements as they move over fieldsets.
- *
- * This function is called on every mouse movement during a Sortables drag.
- *
- * @param e
- *   The event object containing status information about the event.
- * @param ui
- *   The jQuery Sortables object containing information about the sortable.
- */
-Drupal.formBuilder.elementIndent = function(e, ui) {
-  var $placeholder = ui.placeholder;
-  var $helper = ui.helper;
-  var $item = ui.item;
-
-  // Do not affect the elements being dragged from the pallette.
-  if ($item.is('li')) {
-    return;
+    if ($this.hasClass('form-builder-unique') || $this.hasClass('form-builder-wrapper')) {
+      $this.show();
+    }
   }
+  
+  // Remove the placeholders and reset the hover state for all for elements
+  $('#form-builder .form-builder-placeholder').remove();
+  $('#form-builder .form-builder-hover').removeClass('form-builder-hover');
 
-  // Turn on the placeholder item (which is in the final location) to take some stats.
-  $placeholder.css('visibility', 'visible');
-  var difference = $helper.width() - $placeholder.width();
-  var offset = $placeholder.offset().left;
-  $placeholder.css('visibility', 'hidden');
+  Drupal.formBuilder.checkFieldsets();
 
-  // Adjust the helper to match the location and width of the real item.
-  var newWidth = $helper.width() - difference;
-  $helper.css('width', newWidth + 'px');
-  $helper.css('left', offset + 'px');
+  // Scroll the palette into view.
+  $(window).scroll();
 };
 
 /**
@@ -676,43 +680,27 @@ Drupal.formBuilder.elementIndent = function(e, ui) {
  * This function is called every time an element changes positions during
  * a Sortables drag and drop operation.
  *
- * @param e
- *   The event object containing status information about the event.
- * @param ui
- *   The jQuery Sortables object containing information about the sortable.
- * @param
+ * @param exclusions
+ *   An array of DOM objects that contain fieldsets that should not be populated
+ *   with a placeholder even if empty.
  */
-Drupal.formBuilder.checkFieldsets = function(e, ui, expand) {
-  var $fieldsets = $('#form-builder div.form-builder-element > fieldset.form-builder-fieldset');
-  var emptyFieldsets = [];
-
-  // Remove all current fieldset placeholders.
-  $fieldsets.find('.ui-sortable-placeholder').siblings('div.form-builder-empty-placeholder').remove();
-
-  // Find all empty fieldsets.
-  $fieldsets.each(function() {
-    var $this = $(this);
-    // Check for empty collapsible fieldsets.
-    if ($this.children('div.fieldset-wrapper').length) {
-      if ($this.children('div.fieldset-wrapper').children(':not(.description):visible, .ui-sortable-placeholder').length == 0) {
-        emptyFieldsets.push(this);
-      }
+Drupal.formBuilder.checkFieldsets = function(exclusions) {
+  var $wrappers = $('#form-builder div.form-builder-element > fieldset.form-builder-fieldset > div.fieldset-wrapper');
+
+  // Insert a placeholder into all empty fieldset wrappers.
+  $wrappers.each(function() {
+    var children = $(this).children();
+    for(var i in exclusions) {
+      children = children.not(exclusions[i]);
     }
-    // Check for empty normal fieldsets.
-    if ($this.children(':not(legend, .description):visible, .ui-sortable-placeholder').length == 0) {
-      emptyFieldsets.push(this);
-    }
-  });
-
-  // Add a placeholder DIV in the empty fieldsets.
-  $(emptyFieldsets).each(function() {
-    var wrapper = $(this).children('div.fieldset-wrapper').get(0) || this;
-    var $placeholder = $(Drupal.settings.formBuilder.emptyFieldset).css('display', 'none').appendTo(wrapper);
-    if (expand) {
-      $placeholder.slideDown();
+    if (children.length == 0) {
+      // No children, add a placeholder
+      $(this).prepend(Drupal.settings.formBuilder.emptyFieldset);
     }
-    else {
-      $placeholder.css('display', 'block');
+    else if (children.length > 1 && children.hasClass('form-builder-empty-placeholder')) {
+      // The fieldset has at least one element besides the placeholder, remove
+      // the placeholder.
+      $(this).find('.form-builder-empty-placeholder').remove();
     }
   });
 
