diff --git a/core/modules/views/includes/ajax.inc b/core/modules/views/includes/ajax.inc
deleted file mode 100644
index 337524d..0000000
--- a/core/modules/views/includes/ajax.inc
+++ /dev/null
@@ -1,73 +0,0 @@
-<?php
-
-/**
- * @file
- * Handles the server side AJAX interactions of Views.
- */
-
-use Drupal\views\Ajax\HighlightCommand;
-use Drupal\Core\Ajax\OpenModalDialogCommand;
-use Drupal\Core\Ajax\AjaxResponse;
-
-/**
- * @defgroup views_ajax Views AJAX library
- * @{
- * Handles the server side AJAX interactions of Views.
- */
-
-/**
- * Wrapper around drupal_build_form to handle some AJAX stuff automatically.
- * This makes some assumptions about the client.
- */
-function views_ajax_form_wrapper($form_id, &$form_state) {
-  // This won't override settings already in.
-  $form_state += array(
-    'rerender' => FALSE,
-    'no_redirect' => !empty($form_state['ajax']),
-    'no_cache' => TRUE,
-    'build_info' => array(
-      'args' => array(),
-    ),
-  );
-
-  $form = drupal_build_form($form_id, $form_state);
-  $output = drupal_render($form);
-
-  // These forms have the title built in, so set the title here:
-  if (empty($form_state['ajax']) && !empty($form_state['title'])) {
-    $form['#attached']['css'][] = drupal_get_path('module', 'views_ui') . '/css/views_ui.admin.css';
-  }
-
-  if (!empty($form_state['ajax']) && (empty($form_state['executed']) || !empty($form_state['rerender']))) {
-    // If the form didn't execute and we're using ajax, build up a
-    // Ajax command list to execute.
-    $response = new AjaxResponse();
-
-    $display = '';
-    $status_messages = array('#theme' => 'status_messages');
-    if ($messages = drupal_render($status_messages)) {
-      $display = '<div class="views-messages">' . $messages . '</div>';
-    }
-    $display .= $output;
-
-    $title = empty($form_state['title']) ? '' : $form_state['title'];
-    $options = array(
-      'dialogClass' => 'views-ui-dialog',
-      'width' => '50%',
-    );
-
-    $response->addCommand(new OpenModalDialogCommand($title, $display, $options));
-
-    if (!empty($form_state['#section'])) {
-      $response->addCommand(new HighlightCommand('.' . drupal_clean_css_identifier($form_state['#section'])));
-    }
-
-    return $response;
-  }
-
-  return (!empty($form_state['title'])) ? array('#title' => $form_state['title'], '#markup' => $output) : $output;
-}
-
-/**
- * @}
- */
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/FormWrapper.php b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/FormWrapper.php
new file mode 100644
index 0000000..e005d72
--- /dev/null
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/FormWrapper.php
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views_ui\Form\Ajax\FormWrapper.
+ *
+ * @defgroup views_ajax Views AJAX library
+ * @{
+ * Handles the server side AJAX interactions of Views.
+ */
+
+namespace Drupal\views_ui\Form\Ajax;
+
+use Drupal\Core\Ajax\AjaxResponse;
+use Drupal\Core\Ajax\OpenModalDialogCommand;
+use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\views\Ajax\HighlightCommand;
+
+/**
+ * Defines wrapper around the form builder to handle some AJAX stuff.
+ */
+class FormWrapper {
+
+  /**
+   * The form builder.
+   *
+   * @var \Drupal\Core\Form\FormBuilderInterface
+   */
+  protected $formBuilder;
+
+  /**
+   * Constructs a new FormWrapper.
+   *
+   * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
+   *   The form builder.
+   */
+  public function __construct(FormBuilderInterface $form_builder) {
+    $this->formBuilder = $form_builder;
+  }
+
+  /**
+   */
+  public function wrapAjaxForm($form_id, array &$form_state) {
+    // This won't override settings already in.
+    $form_state += array(
+      'rerender' => FALSE,
+      'no_redirect' => !empty($form_state['ajax']),
+      'no_cache' => TRUE,
+      'build_info' => array(
+        'args' => array(),
+      ),
+    );
+
+    $form = $this->formBuilder->buildForm($form_id, $form_state);
+
+    // These forms have the title built in, so set the title here:
+    if (empty($form_state['ajax']) && !empty($form_state['title'])) {
+      $form['#attached']['library'][] = array('views_ui', 'views_ui.admin');
+    }
+    $output = $this->drupalRender($form);
+
+    if (!empty($form_state['ajax']) && (empty($form_state['executed']) || !empty($form_state['rerender']))) {
+      // If the form didn't execute and we're using ajax, build up a
+      // Ajax command list to execute.
+      $response = new AjaxResponse();
+
+      $display = '';
+      $status_messages = array('#theme' => 'status_messages');
+      if ($messages = $this->drupalRender($status_messages)) {
+        $display = '<div class="views-messages">' . $messages . '</div>';
+      }
+      $display .= $output;
+
+      $title = empty($form_state['title']) ? '' : $form_state['title'];
+      $options = array(
+        'dialogClass' => 'views-ui-dialog',
+        'width' => '50%',
+      );
+
+      $response->addCommand(new OpenModalDialogCommand($title, $display, $options));
+
+      if (!empty($form_state['#section'])) {
+        $response->addCommand(new HighlightCommand('.' . $this->drupalCleanCssIdentifier($form_state['#section'])));
+      }
+
+      return $response;
+    }
+
+    return (!empty($form_state['title'])) ? array('#title' => $form_state['title'], '#markup' => $output) : $output;
+  }
+
+  /**
+   * Wraps drupal_render.
+   *
+   * @param array $elements
+   *   The structured array describing the data to be rendered.
+   *
+   * @return string
+   *   The rendered HTML.
+   */
+  protected function drupalRender(array $elements) {
+    return drupal_render($elements);
+  }
+
+  /**
+   * Wraps drupal_clean_css_identifier.
+   *
+   * @param string $identifier
+   *   The identifier to clean.
+   *
+   * @return string
+   *   The cleaned identifier.
+   */
+  protected function drupalCleanCssIdentifier($identifier) {
+    return drupal_clean_css_identifier($identifier);
+  }
+
+}
+
+/**
+ * @}
+ */
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ViewsFormBase.php b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ViewsFormBase.php
index 2f1273c..5813e1e 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ViewsFormBase.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ViewsFormBase.php
@@ -34,6 +34,13 @@
   protected $type;
 
   /**
+   * The views ajax form wrapper.
+   *
+   * @var \Drupal\views_ui\Form\Ajax\FormWrapper
+   */
+  protected $ajaxFormWrapper;
+
+  /**
    * Sets the ID for this form.
    *
    * @param string $id
@@ -58,6 +65,19 @@ protected function setType($type) {
   }
 
   /**
+   * Gets the views ajax form wrapper.
+   *
+   * @return \Drupal\views_ui\Form\Ajax\FormWrapper
+   *   The views ajax form wrapper.
+   */
+  protected function getAjaxFormWrapper() {
+    if (!isset($this->ajaxFormWrapper)) {
+      $this->ajaxFormWrapper = \Drupal::service('views_ui.ajax_form_wrapper');
+    }
+    return $this->ajaxFormWrapper;
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function getFormState(ViewStorageInterface $view, $display_id, $js) {
@@ -89,7 +109,6 @@ public function getForm(ViewStorageInterface $view, $display_id, $js) {
 
     // @todo Remove the need for this.
     \Drupal::moduleHandler()->loadInclude('views_ui', 'inc', 'admin');
-    \Drupal::moduleHandler()->loadInclude('views', 'inc', 'includes/ajax');
 
     // Reset the cache of IDs. Drupal rather aggressively prevents ID
     // duplication but this causes it to remember IDs that are no longer even
@@ -127,7 +146,7 @@ public function getForm(ViewStorageInterface $view, $display_id, $js) {
     // reset the _drupal_add_js() static before rendering the second time.
     $drupal_add_js_original = _drupal_add_js();
     $drupal_add_js = &drupal_static('_drupal_add_js');
-    $response = views_ajax_form_wrapper($form_state['form_id'], $form_state);
+    $response = $this->getAjaxFormWrapper()->wrapAjaxForm($form_state['form_id'], $form_state);
 
     // If the form has not been submitted, or was not set for rerendering, stop.
     if (!$form_state['submitted'] || !empty($form_state['rerender'])) {
@@ -150,7 +169,7 @@ public function getForm(ViewStorageInterface $view, $display_id, $js) {
         return new RedirectResponse(url($form_path, array('absolute' => TRUE)));
       }
       $form_state['path'] = $form_path;
-      $response = views_ajax_form_wrapper($form_state['form_id'], $form_state);
+      $response = $this->getAjaxFormWrapper()->wrapAjaxForm($form_state['form_id'], $form_state);
     }
     elseif (!$form_state['ajax']) {
       // if nothing on the stack, non-js forms just go back to the main view editor.
diff --git a/core/modules/views_ui/tests/Drupal/views_ui/Tests/Form/Ajax/FormWrapperTest.php b/core/modules/views_ui/tests/Drupal/views_ui/Tests/Form/Ajax/FormWrapperTest.php
new file mode 100644
index 0000000..5123c27
--- /dev/null
+++ b/core/modules/views_ui/tests/Drupal/views_ui/Tests/Form/Ajax/FormWrapperTest.php
@@ -0,0 +1,180 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views_ui\Tests\Form\Ajax\FormWrapperTest.
+ */
+
+namespace Drupal\views_ui\Tests\Form\Ajax {
+
+use Drupal\Core\Form\FormInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views_ui\Form\Ajax\FormWrapper;
+
+/**
+ * Tests the ajax form wrapper.
+ *
+ * @see \Drupal\views_ui\Form\Ajax\FormWrapper
+ */
+class FormWrapperTest extends UnitTestCase {
+
+  /**
+   * The tested form wrapper.
+   *
+   * @var \Drupal\views_ui\Form\Ajax\FormWrapper|\Drupal\views_ui\Tests\Form\Ajax\TestFormWrapper
+   */
+  protected $formWrapper;
+
+  /**
+   * The mocked form builder.
+   *
+   * @var \Drupal\Core\Form\FormBuilderInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $formBuilder;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Ajax form wrapper',
+      'description' => 'Tests the ajax form wrapper',
+      'group' => 'Views UI',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->formBuilder = $this->getMock('Drupal\Core\Form\FormBuilderInterface');
+    $this->formWrapper = new TestFormWrapper($this->formBuilder);
+    $this->formBuilder->expects($this->any())
+      ->method('buildForm')
+      ->will($this->returnCallback(function (FormInterface $form_object, $form_state) {
+        $form = array();
+        return $form_object->buildForm($form, $form_state);
+      }));
+  }
+
+  /**
+   * Tests wrapAjaxForm on a non AJAX request without a title.
+   */
+  public function testWrapAjaxFormOnNonAjaxRequest() {
+    $form_object = new TestForm();
+    $form_state = array();
+
+    $output = $this->formWrapper->wrapAjaxForm($form_object, $form_state);
+    $this->assertEquals('Test form', $output);
+  }
+
+  /**
+   * Tests wrapAjaxForm on a non AJAX request but with a title.
+   */
+  public function testWrapAjaxFormOnNonAjaxRequestWithTitle() {
+    $form_object = new TestForm();
+    $form_state = array(
+      'title' => 'Test title',
+    );
+
+    $output = $this->formWrapper->wrapAjaxForm($form_object, $form_state);
+    $this->assertEquals('Test form views_ui:views_ui.admin', $output);
+  }
+
+  /**
+   * Tests wrapAjaxForm on a AJAX request.
+   */
+  public function testWrapAjaxOnAjaxRequest() {
+    $form_object = new TestForm();
+    $form_state = array(
+      'ajax' => TRUE,
+      'title' => 'Test title',
+    );
+
+    $output = $this->formWrapper->wrapAjaxForm($form_object, $form_state);
+    $this->assertInstanceOf('Drupal\Core\Ajax\AjaxResponse', $output);
+
+    $commands = static::readAttribute($output, 'commands');
+
+    $dialog_command = $commands[0];
+    $this->assertEquals('openDialog', $dialog_command['command']);
+    $this->assertEquals('views-ui-dialog', $dialog_command['dialogOptions']['dialogClass']);
+    $this->assertEquals('Test title', $dialog_command['dialogOptions']['title']);
+    $this->assertTrue($dialog_command['dialogOptions']['modal']);
+  }
+
+  /**
+   * Tests wrapAjaxForm with a specified section.
+   */
+  public function testWrapAjaxWithSection() {
+    $form_object = new TestForm();
+    $form_state = array(
+      'ajax' => TRUE,
+      '#section' => 'example-section',
+    );
+
+    $output = $this->formWrapper->wrapAjaxForm($form_object, $form_state);
+    $this->assertInstanceOf('Drupal\Core\Ajax\AjaxResponse', $output);
+
+    $commands = static::readAttribute($output, 'commands');
+    $highlight_command = $commands[1];
+
+    $this->assertEquals('openDialog', $commands[0]['command']);
+
+    $this->assertEquals('viewsHighlight', $highlight_command['command']);
+    $this->assertEquals('.example-section', $highlight_command['selector']);
+  }
+
+}
+
+class TestFormWrapper extends FormWrapper {
+
+  protected function drupalRender(array $elements) {
+
+    if (isset($elements['#markup'])) {
+      $library = isset($elements['#attached']) ? ' ' . implode(':', $elements['#attached']['library'][0]) : '';
+      return $elements['#markup'] . $library;
+    }
+    elseif (isset($elements['#theme']) && $elements['#theme'] == 'status_messages') {
+      return '';
+    }
+  }
+
+  protected function drupalCleanCssIdentifier($identifier) {
+    return $identifier;
+  }
+
+}
+
+class TestForm implements FormInterface {
+
+  public function getFormId() {
+    return 'test_form';
+  }
+
+  public function buildForm(array $form, array &$form_state) {
+    $form = array(
+      '#markup' => 'Test form',
+    );
+    return $form;
+  }
+
+  public function validateForm(array &$form, array &$form_state) {
+
+  }
+
+  public function submitForm(array &$form, array &$form_state) {
+
+  }
+
+}
+
+}
+
+namespace {
+  if (!function_exists('drupal_add_library')) {
+    function drupal_add_library() {
+      return TRUE;
+    }
+  }
+}
diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module
index f90508c..fe74c4e 100644
--- a/core/modules/views_ui/views_ui.module
+++ b/core/modules/views_ui/views_ui.module
@@ -157,15 +157,20 @@ function views_ui_permission() {
 function views_ui_library_info() {
   $libraries = array();
 
-  $path = drupal_get_path('module', 'views_ui') . '/js/';
+  $path = drupal_get_path('module', 'views_ui');
+  $path_js = $path . '/js/';
+  $path_css = $path . '/css/';
 
   $libraries['views_ui.admin'] = array(
     'title' => 'Views UI ADMIN',
     'version' => \Drupal::VERSION,
     'js' => array(
-      $path . 'ajax.js' => array('group' => JS_DEFAULT),
-      $path . 'dialog.views.js' => array('group' => JS_DEFAULT),
-      $path . 'views-admin.js' => array('group' => JS_DEFAULT),
+      $path_js . 'ajax.js' => array('group' => JS_DEFAULT),
+      $path_js . 'dialog.views.js' => array('group' => JS_DEFAULT),
+      $path_js . 'views-admin.js' => array('group' => JS_DEFAULT),
+    ),
+    'css' => array(
+      $path_css . 'views_ui.admin.css',
     ),
     'dependencies' => array(
       array('system', 'jquery'),
@@ -182,7 +187,7 @@ function views_ui_library_info() {
     'title' => 'Views UI listing',
     'version' => Drupal::VERSION,
     'js' => array(
-      $path . 'views_ui.listing.js' => array('group' => JS_DEFAULT),
+      $path_js . 'views_ui.listing.js' => array('group' => JS_DEFAULT),
     ),
   );
 
diff --git a/core/modules/views_ui/views_ui.services.yml b/core/modules/views_ui/views_ui.services.yml
index e75c7af..71626c5 100644
--- a/core/modules/views_ui/views_ui.services.yml
+++ b/core/modules/views_ui/views_ui.services.yml
@@ -4,3 +4,6 @@ services:
     arguments: ['@entity.manager', '@user.tempstore']
     tags:
       - { name: paramconverter, priority: 10 }
+  views_ui.ajax_form_wrapper:
+    class: Drupal\views_ui\Form\Ajax\FormWrapper
+    arguments: ['@form_builder']
