diff --git a/core/core.libraries.yml b/core/core.libraries.yml
index 41406af..b259302 100644
--- a/core/core.libraries.yml
+++ b/core/core.libraries.yml
@@ -91,7 +91,7 @@ drupal.autocomplete:
     - core/drupal
     - core/drupalSettings
     - core/drupal.ajax
-    - core/jquery.ui.autocomplete
+    - core/select2
 
 drupal.batch:
   version: VERSION
@@ -797,3 +797,19 @@ underscore:
     gpl-compatible: true
   js:
     assets/vendor/underscore/underscore.js: { weight: -20 }
+
+select2:
+  remote: https://github.com/ivaynberg/select2
+  version: 3.5.2
+  license:
+    name: GNU-GPL-2.0-or-later
+    url: https://github.com/ivaynberg/select2/blob/master/LICENSE
+    gpl-compatible: true
+  js:
+    assets/vendor/select2/select2.js: {}
+    misc/select2.js: {}
+  css:
+    theme:
+      assets/vendor/select2/select2.css: {}
+  dependencies:
+    - core/jquery
diff --git a/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php b/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php
index 79d9082..0e67b5e 100644
--- a/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php
@@ -67,6 +67,8 @@ public function buildForm(array $form, FormStateInterface $form_state, $install_
       '#options' => $select_options,
       // Use the browser detected language as default or English if nothing found.
       '#default_value' => !empty($browser_langcode) ? $browser_langcode : 'en',
+      // Use the Select2 library.
+      '#select2' => TRUE,
     );
     $form['help'] = array(
       '#type' => 'item',
diff --git a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
index 1674211..3449ec5 100644
--- a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
@@ -200,6 +200,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#description' => $this->t('By default, dates in this site will be displayed in the chosen time zone.'),
       '#weight' => 5,
       '#attributes' => array('class' => array('timezone-detect')),
+      // Use the Select2 library.
+      '#select2' => TRUE,
     );
 
     $form['update_notifications'] = array(
diff --git a/core/lib/Drupal/Core/Render/Element/FormElement.php b/core/lib/Drupal/Core/Render/Element/FormElement.php
index 401c850..3027540 100644
--- a/core/lib/Drupal/Core/Render/Element/FormElement.php
+++ b/core/lib/Drupal/Core/Render/Element/FormElement.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Render\Element;
 
+use Drupal\Component\Serialization\Json;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
@@ -128,4 +129,43 @@ public static function processAutocomplete(&$element, FormStateInterface $form_s
     return $element;
   }
 
+  /**
+   * Integrates form elements with the Select2 JavaScript library.
+   *
+   * @param array $element
+   *   The form element to process. Properties used:
+   *   - #select2: Whether to use the Select2 library for this form element. If
+   *     the value is TRUE, the Select2 library is initialized with its default
+   *     options. If the value is an array, each key and value will map to the
+   *     corresponding Select2 configuration.
+   *     @see http://ivaynberg.github.io/select2/#documentation for the list of
+   *     possible configuration options.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param array $complete_form
+   *   The complete form structure.
+   *
+   * @return array
+   *   The form element.
+   */
+  public static function processSelect2(&$element, FormStateInterface $form_state, &$complete_form) {
+    if (!empty($element['#select2'])) {
+      // Provide some default options.
+      // @todo Figure out if we need more defaults here.
+      $configuration = array(
+        'width' => 'resolve',
+      );
+      if (is_array($element['#select2'])) {
+        $configuration = $element['#select2'] + $configuration;
+      }
+
+      $element['#attributes']['class'][] = 'form-select2';
+      $element['#attached']['library'][] = 'core/select2';
+      // Provide a data attribute which stores the Select2 configuration array.
+      $element['#attributes']['data-drupal-select2'] = Json::encode($configuration);
+    }
+
+    return $element;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Render/Element/Select.php b/core/lib/Drupal/Core/Render/Element/Select.php
index 70f14d6..4507fdb 100644
--- a/core/lib/Drupal/Core/Render/Element/Select.php
+++ b/core/lib/Drupal/Core/Render/Element/Select.php
@@ -31,6 +31,9 @@ public function getInfo() {
       '#process' => array(
         array($class, 'processSelect'),
         array($class, 'processAjaxForm'),
+        // Not to be confused with the processor above, this one is about the
+        // Select2 Javascript library.
+        array($class, 'processSelect2'),
       ),
       '#pre_render' => array(
         array($class, 'preRenderSelect'),
diff --git a/core/misc/autocomplete.js b/core/misc/autocomplete.js
index af64521..dfe5350 100644
--- a/core/misc/autocomplete.js
+++ b/core/misc/autocomplete.js
@@ -2,171 +2,7 @@
 
   "use strict";
 
-  var autocomplete;
-
-  /**
-   * Helper splitting terms from the autocomplete value.
-   *
-   * @param {String} value
-   *
-   * @return {Array}
-   */
-  function autocompleteSplitValues(value) {
-    // We will match the value against comma-separated terms.
-    var result = [];
-    var quote = false;
-    var current = '';
-    var valueLength = value.length;
-    var i, character;
-
-    for (i = 0; i < valueLength; i++) {
-      character = value.charAt(i);
-      if (character === '"') {
-        current += character;
-        quote = !quote;
-      }
-      else if (character === ',' && !quote) {
-        result.push(current.trim());
-        current = '';
-      }
-      else {
-        current += character;
-      }
-    }
-    if (value.length > 0) {
-      result.push($.trim(current));
-    }
-
-    return result;
-  }
-
-  /**
-   * Returns the last value of an multi-value textfield.
-   *
-   * @param {String} terms
-   *
-   * @return {String}
-   */
-  function extractLastTerm(terms) {
-    return autocomplete.splitValues(terms).pop();
-  }
-
-  /**
-   * The search handler is called before a search is performed.
-   *
-   * @param {Object} event
-   *
-   * @return {Boolean}
-   */
-  function searchHandler(event) {
-    // Only search when the term is two characters or larger.
-    var term = autocomplete.extractLastTerm(event.target.value);
-    return term.length >= autocomplete.minLength;
-  }
-
-  /**
-   * jQuery UI autocomplete source callback.
-   *
-   * @param {Object} request
-   * @param {Function} response
-   */
-  function sourceData(request, response) {
-    /*jshint validthis:true */
-    var elementId = this.element.attr('id');
-
-    if (!(elementId in autocomplete.cache)) {
-      autocomplete.cache[elementId] = {};
-    }
-
-    /**
-     * Filter through the suggestions removing all terms already tagged and
-     * display the available terms to the user.
-     *
-     * @param {Object} suggestions
-     */
-    function showSuggestions(suggestions) {
-      var tagged = autocomplete.splitValues(request.term);
-      for (var i = 0, il = tagged.length; i < il; i++) {
-        var index = suggestions.indexOf(tagged[i]);
-        if (index >= 0) {
-          suggestions.splice(index, 1);
-        }
-      }
-      response(suggestions);
-    }
-
-    /**
-     * Transforms the data object into an array and update autocomplete results.
-     *
-     * @param {Object} data
-     */
-    function sourceCallbackHandler(data) {
-      autocomplete.cache[elementId][term] = data;
-
-      // Send the new string array of terms to the jQuery UI list.
-      showSuggestions(data);
-    }
-
-    // Get the desired term and construct the autocomplete URL for it.
-    var term = autocomplete.extractLastTerm(request.term);
-
-    // Check if the term is already cached.
-    if (autocomplete.cache[elementId].hasOwnProperty(term)) {
-      showSuggestions(autocomplete.cache[elementId][term]);
-    }
-    else {
-      var options = $.extend({ success: sourceCallbackHandler, data: { q: term } }, autocomplete.ajax);
-      /*jshint validthis:true */
-      $.ajax(this.element.attr('data-autocomplete-path'), options);
-    }
-  }
-
-  /**
-   * Handles an autocompletefocus event.
-   *
-   * @return {Boolean}
-   */
-  function focusHandler() {
-    return false;
-  }
-
-  /**
-   * Handles an autocompleteselect event.
-   *
-   * @param {Object} event
-   * @param {Object} ui
-   *
-   * @return {Boolean}
-   */
-  function selectHandler(event, ui) {
-    var terms = autocomplete.splitValues(event.target.value);
-    // Remove the current input.
-    terms.pop();
-    // Add the selected item.
-    if (ui.item.value.search(",") > 0) {
-      terms.push('"' + ui.item.value + '"');
-    }
-    else {
-      terms.push(ui.item.value);
-    }
-    event.target.value = terms.join(', ');
-    // Return false to tell jQuery UI that we've filled in the value already.
-    return false;
-  }
-
-  /**
-   * Override jQuery UI _renderItem function to output HTML by default.
-   *
-   * @param {Object} ul
-   * @param {Object} item
-   *
-   * @return {Object}
-   */
-  function renderItem(ul, item) {
-    return $("<li>")
-      .append($("<a>").html(item.label))
-      .appendTo(ul);
-  }
+  var select2Options = {};
 
   /**
    * Attaches the autocomplete behavior to all required fields.
@@ -174,45 +10,42 @@
   Drupal.behaviors.autocomplete = {
     attach: function (context) {
       // Act on textfields with the "form-autocomplete" class.
-      var $autocomplete = $(context).find('input.form-autocomplete').once('autocomplete');
-      if ($autocomplete.length) {
-        // Use jQuery UI Autocomplete on the textfield.
-        $autocomplete.autocomplete(autocomplete.options)
-          .data("ui-autocomplete")
-          ._renderItem = autocomplete.options.renderItem;
-      }
-    },
-    detach: function (context, settings, trigger) {
-      if (trigger === 'unload') {
-        $(context).find('input.form-autocomplete')
-          .removeOnce('autocomplete')
-          .autocomplete('destroy');
-      }
+      var $autocomplete = $(context).find('input.form-autocomplete').once('autocomplete')
+        .each(function () {
+          $(this).select2({
+            tokenSeparators: [","],
+            tags: [],
+            minimumInputLength: 1,
+            quietMills: 200,
+            cache: true,
+            width: 'resolve',
+            initSelection: function (element, callback) {
+              var data = element.val().split(',').map(function (value) {
+                return {id: value, text: value};
+              });
+              callback(data);
+            },
+            createSearchChoice: function (term) {
+              return {id: term, text: term};
+            },
+            ajax: {
+              dataType: 'json',
+              url: $(this).attr('data-autocomplete-path'),
+              data: function (term, page) {
+                return {q: term};
+              },
+              results: function (data, page) {
+                return {
+                  // Transform Drupal autocomplete format to select2 format.
+                  results: data.map(function (result) {
+                    return {id: result.value, text: result.label};
+                  })
+                };
+              }
+            }
+          });
+        });
     }
   };
 
-  /**
-   * Autocomplete object implementation.
-   */
-  autocomplete = {
-    cache: {},
-    // Exposes methods to allow overriding by contrib.
-    minLength: 1,
-    splitValues: autocompleteSplitValues,
-    extractLastTerm: extractLastTerm,
-    // jQuery UI autocomplete options.
-    options: {
-      source: sourceData,
-      focus: focusHandler,
-      search: searchHandler,
-      select: selectHandler,
-      renderItem: renderItem
-    },
-    ajax: {
-      dataType: 'json'
-    }
-  };
-
-  Drupal.autocomplete = autocomplete;
-
 })(jQuery, Drupal);
diff --git a/core/misc/drupal.js b/core/misc/drupal.js
index dcfad00..ccb88c4 100644
--- a/core/misc/drupal.js
+++ b/core/misc/drupal.js
@@ -86,12 +86,12 @@ if (window.jQuery) {
     for (i in behaviors) {
       if (behaviors.hasOwnProperty(i) && typeof behaviors[i].attach === 'function') {
         // Don't stop the execution of behaviors in case of an error.
-        try {
+        //try {
           behaviors[i].attach(context, settings);
-        }
-        catch (e) {
-          errors.push({ behavior: i, error: e });
-        }
+        //}
+        //catch (e) {
+          //errors.push({ behavior: i, error: e });
+        //}
       }
     }
     // Once all behaviors have been processed, inform the user about errors.
diff --git a/core/misc/select2.js b/core/misc/select2.js
new file mode 100644
index 0000000..db320ec
--- /dev/null
+++ b/core/misc/select2.js
@@ -0,0 +1,17 @@
+(function ($, Drupal) {
+
+  "use strict";
+
+  /**
+   * Attaches the Select2 behavior to all form elements that requested it.
+   */
+  Drupal.behaviors.select2 = {
+    attach: function (context) {
+      $(context).find('[data-drupal-select2]').once('drupal-select2')
+        .each(function () {
+          $(this).select2(JSON.parse(this.getAttribute('data-drupal-select2')));
+        });
+    }
+  };
+
+})(jQuery, Drupal);
diff --git a/core/modules/system/src/Form/RegionalForm.php b/core/modules/system/src/Form/RegionalForm.php
index 2d3934f..0550370 100644
--- a/core/modules/system/src/Form/RegionalForm.php
+++ b/core/modules/system/src/Form/RegionalForm.php
@@ -98,6 +98,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#title' => t('Default time zone'),
       '#default_value' => $system_date->get('timezone.default') ?: date_default_timezone_get(),
       '#options' => $zones,
+      // Use the Select2 library.
+      '#select2' => TRUE,
     );
 
     $configurable_timezones = $system_date->get('timezone.user.configurable');
