diff --git a/panopoly-magic.js b/panopoly-magic.js
index f52f96b..9d34130 100644
--- a/panopoly-magic.js
+++ b/panopoly-magic.js
@@ -27,6 +27,14 @@
    */
   Drupal.behaviors.panopolyMagicAutosubmit = {
     attach: function (context, settings) {
+      // Replaces click with mousedown for submit so both normal and ajax work.
+      $('.ctools-auto-submit-click', context).click(function(event) {
+        if ($(this).hasClass('ajax-processed')) {
+          event.stopImmediatePropagation();
+          $(this).trigger('mousedown');
+          return false;
+        }
+      });
       // 'this' references the form element
       function triggerSubmit (e) {
         var $this = $(this);
diff --git a/panopoly_magic.module b/panopoly_magic.module
index 7fe100c..efd708a 100644
--- a/panopoly_magic.module
+++ b/panopoly_magic.module
@@ -1,5 +1,4 @@
 <?php
-
 include_once('panopoly_magic.features.inc');
 
 /**
@@ -32,6 +31,56 @@ function panopoly_magic_init() {
 }
 
 /**
+ * Implements hook_menu()
+ */
+function panopoly_magic_menu() {
+  $items = array();
+  $items['system/panopoly-magic'] = array(
+    'title' => 'AHAH callback',
+    'page callback' => 'panopoly_magic_ajax_form_callback',
+    'delivery callback' => 'ajax_deliver',
+    'access callback' => TRUE,
+    'theme callback' => 'ajax_base_page_theme',
+    'type' => MENU_CALLBACK,
+    'file path' => 'includes',
+    'file' => 'form.inc',
+  );
+  return $items;
+}
+
+/**
+ * Replaces system/ajax for pane configuration preview callback to work with
+ * ctools multi step form.
+ */
+function panopoly_magic_ajax_form_callback() {
+  list($form, $form_state) = ajax_get_form();
+  ctools_include('content');
+  ctools_include('modal');
+
+  if (isset($form_state['no_redirect']) && !isset($form_state['form_info'])) {
+    $form_state += array(
+      're_render' => FALSE,
+      'no_redirect' => !empty($form_state['ajax']),
+     );
+     $form= drupal_build_form($form_state['build_info']['form_id'], $form_state);
+  }
+  else {
+    // These ensure the class files/form definations are included.
+    $content_type = ctools_get_content_type($form_state['pane']->type);
+    $subtype = ctools_content_get_subtype($content_type, $form_state['subtype_name']);
+
+    $form  = ctools_content_form($form_state['op'], $form_state['form_info'], $form_state, $form_state['plugin'], $form_state['subtype_name'], $form_state['conf'], $form_state['step']);
+  }
+
+  if (!empty($form_state['triggering_element'])) {
+    $callback = $form_state['triggering_element']['#ajax']['callback'];
+  }
+  if (!empty($callback) && function_exists($callback)) {
+    return $callback($form, $form_state);
+  }
+}
+
+/**
  * Implements hook_apps_app_info()
  */
 function panopoly_magic_apps_app_info() {
@@ -292,21 +341,21 @@ function panopoly_magic_form_alter(&$form, &$form_state, $form_id) {
         unset($configuration['image_link']);
       }
     }
-    $content = (empty($preview_subtype)) ? ctools_content_render($pane->type, $pane->subtype, $configuration, $keywords, $args, $context) : ctools_content_render($pane->type, $preview_subtype, $configuration, $keywords, $args, $context);
-
-    // Create the preview fieldset
-    if ($form_id == 'fieldable_panels_panes_fieldable_panels_pane_content_type_edit_form' || is_object($content)) {
 
-      // Create the fieldset with appropriate content
-      $form['widget_preview'] = array(
-        '#type' => 'fieldset',
-        '#title' => t('Preview'),
-        '#attributes' => array('class' => array('widget-preview', 'widget-preview-single')),
-        '#collapsible' => FALSE,
-        '#weight' => -100,
-      );
-      $form['widget_preview']['preview'] = array(
-        '#markup' => (!empty($style['render pane'])) ? theme($style['render pane'], array('content' => $content, 'pane' => $pane, 'display' => $display, 'style' => $style, 'settings' => $pane->style['settings'])) : theme('panels_pane', array('content' => $content, 'pane' => $pane, 'display' => $display)),
+    // only render preview for Panes and not Regions
+    if (isset($pane)) {
+      // Creates preview outside of form itself to fix various bugs, like form
+      // inside form and double rendering.
+      $form['#post_render'][] = 'panopoly_magic_form_post_render_preview';
+      $form['#panopoly_magic_preview_info'] = array(
+        'preview_subtype' => isset($preview_subtype) ? $preview_subtype : NULL,
+        'pane' => $pane,
+        'configuration' =>  $configuration,
+        'keywords' => $keywords,
+        'args' => $args,
+        'context' => $context,
+        'style' => $style,
+        'display' => $display,
       );
 
       // Remove the clearfix for preview floating
@@ -317,7 +366,6 @@ function panopoly_magic_form_alter(&$form, &$form_state, $form_id) {
       $preview_attributes = array(
         'class' => array(
           'widget-preview-button',
-          'ctools-use-ajax',
         ),
       );
 
@@ -331,14 +379,20 @@ function panopoly_magic_form_alter(&$form, &$form_state, $form_id) {
       $form['buttons']['preview'] = array(
         '#type' => 'button',
         '#value' => t('Update Preview'),
-        '#wizard type' => 'next',
         '#attributes' => $preview_attributes,
+        '#ajax' => array(
+          'callback' => 'panopoly_magic_ajax_update_preview',
+          'wrapper' => 'panopoly-form-widget-preview',
+          'path' => 'system/panopoly-magic',
+        ),
       );
 
       // Autosubmit the form
       ctools_add_js('auto-submit');
       $form['#attributes']['class'][] = 'ctools-auto-submit-full-form';
     }
+    // Convert any other #ajax enabled buttons to use system/panopoly-magic.
+    _panopoly_magic_add_path_to_ajax($form);
   }
   
    /**
@@ -349,7 +403,7 @@ function panopoly_magic_form_alter(&$form, &$form_state, $form_id) {
     if (!empty($form['buttons']['return'])) {
       $form['buttons']['return']['#value'] = t('Save');
     }
-    $form['buttons']['#weight'] = (!empty($form['widget_preview']['#weight'])) ? ($form['widget_preview']['#weight'] +1 ): -99;
+    $form['buttons']['#weight'] = -99;
   }
 
   /**
@@ -405,6 +459,58 @@ function panopoly_magic_form_alter(&$form, &$form_state, $form_id) {
 }
 
 /**
+ * Content panes should not use default system/ajax. Use our own for now.
+ */
+function _panopoly_magic_add_path_to_ajax($element) {
+  if (!empty($element['#ajax']) && !isset($element['#ajax']['path'])) {
+    $element['#ajax']['path'] = 'system/panopoly-magic';
+  }
+  foreach (element_children($element) as $key) {
+    _panopoly_magic_add_path_to_ajax($element[$key]);
+  }
+}
+
+/**
+ * Ajax callback that just returns the rendered preview.
+ */
+function panopoly_magic_ajax_update_preview($form, $form_state) {
+  return;
+  if (isset($form_state['values']) && isset($form['#panopoly_magic_preview_info']['configuration'])) {
+    $form['#panopoly_magic_preview_info']['configuration'] = $form_state['values'] + $form['#panopoly_magic_preview_info']['configuration'];
+  }
+  return panopoly_magic_form_post_render_preview('', $form);
+}
+
+/**
+ * Add the preview to the form output.
+ *
+ * It is done here so the form is fully processed.
+ */
+function panopoly_magic_form_post_render_preview($output, $form) {
+  extract($form['#panopoly_magic_preview_info']);
+  $content = (empty($preview_subtype)) ? ctools_content_render($pane->type, $pane->subtype, $configuration, $keywords, $args, $context) : ctools_content_render($pane->type, $preview_subtype, $configuration, $keywords, $args, $context);
+
+  // Create the fieldset with appropriate content
+  $preview = array(
+    '#type' => 'fieldset',
+    '#title' => 'Preview',
+    '#attributes' => array(
+      'id' => 'panopoly-form-widget-preview',
+      'class' => array('widget-preview', 'widget-preview-single'),
+    ),
+    '#collapsible' => FALSE,
+    '#weight' => -100,
+  );
+  if (!empty($content)) {
+    $preview['preview']['#markup'] = (!empty($style['render pane'])) ? theme($style['render pane'], array('content' => $content, 'pane' => $pane, 'display' => $display, 'style' => $style, 'settings' => $pane->style['settings'])) : theme('panels_pane', array('content' => $content, 'pane' => $pane, 'display' => $display));
+  }
+  else {
+    $preview['preview']['#markup'] = t('[no preview]');
+  }
+  return drupal_render($preview) . $output;
+}
+
+/**
  * Recursively parse form elements to add special autosubmit handling on a per field-type basis.
  */
 function panopoly_magic_autosubmit_configure(&$element) {
@@ -722,7 +828,6 @@ function panopoly_magic_form_views_content_views_panes_content_type_edit_form_al
 
   // Add a custom submit handler to our preview and submit option
   $form['#submit'][] = 'panopoly_magic_views_content_type_modal_submit';
-  $form['buttons']['preview']['#submit'][] = 'panopoly_magic_views_content_type_modal_submit';
 }
 
 /**
