diff --git a/core/includes/form.inc b/core/includes/form.inc
index d602d54..0dc2ab2 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -1907,6 +1907,23 @@ function form_builder($form_id, &$element, &$form_state) {
     $element['#processed'] = TRUE;
   }
 
+  // Checks if the element needs property validation.
+  if (isset($element['#property_validate']) && is_array($element['#property_validate'])) {
+    // Validates required properties.
+    foreach ($element['#property_validate'] as $property => $callbacks) {
+      foreach ($callbacks as $callback) {
+        if (!isset($element[$property]) || !$callback($element)) {
+          trigger_error(t("'@type' element in form '@form_id' has a non-valid '@property' property in @parents.", array(
+            '@type' => $element['#type'],
+            '@form_id' => $form_id,
+            '@property' => $property,
+            '@parents' => '$form[\'' . implode('\'][\'', $element['#parents']) . '\']',
+          )), E_USER_ERROR);
+        }
+      }
+    }
+  }
+
   // We start off assuming all form elements are in the correct order.
   $element['#sorted'] = TRUE;
 
@@ -3360,6 +3377,20 @@ function form_pre_render_actions_dropbutton(array $element) {
 }
 
 /**
+ * Validates the title property of a form component that requires it.
+ *
+ * @param array $element
+ *   The element definition to validate #title for.
+ *
+ * @return bool
+ */
+function form_element_validate_title(&$element) {
+  // Ensures that $title does not start with, end with or contain only spaces,
+  // and that it contains a string by verifying its length.
+  return strlen(trim($element['#title'])) !== 0;
+}
+
+/**
  * #process callback for #pattern form element property.
  *
  * @param $element
@@ -3586,6 +3617,7 @@ function form_process_tableselect($element) {
             '#parents' => $element['#parents'],
             '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)),
             '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
+            '#property_validate' => array(),
           );
         }
         if (isset($element['#options'][$key]['#weight'])) {
@@ -4009,6 +4041,16 @@ function form_process_vertical_tabs($element, &$form_state) {
     '#parents' => $element['#parents'],
   );
 
+  // Details within a vertical tab do not require a title.
+  $details_validation = element_info_property('details', '#property_validate');
+  if (isset($details_validation['#title'])) {
+    $key = array_search('form_element_validate_title', $details_validation['#title']);
+    if ($key !== FALSE) {
+      unset($details_validation['#title'][$key]);
+    }
+  }
+  $element['group']['#property_validate'] = $details_validation;
+
   // Add an invisible label for accessibility.
   if (!isset($element['#title'])) {
     $element['#title'] = t('Vertical Tabs');
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index eefe926..58d66e3 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -2462,6 +2462,7 @@ function _install_configure_form($form, &$form_state, &$install_state) {
   );
   $form['update_notifications']['update_status_module'] = array(
     '#type' => 'checkboxes',
+    '#title' => t('Update notifications'),
     '#options' => array(
       1 => t('Check for updates automatically'),
       2 => t('Receive e-mail notifications'),
diff --git a/core/modules/action/lib/Drupal/action/ActionFormControllerBase.php b/core/modules/action/lib/Drupal/action/ActionFormControllerBase.php
index ff48164..f14b05f 100644
--- a/core/modules/action/lib/Drupal/action/ActionFormControllerBase.php
+++ b/core/modules/action/lib/Drupal/action/ActionFormControllerBase.php
@@ -79,7 +79,6 @@ public function form(array $form, array &$form_state) {
 
     $form['id'] = array(
       '#type' => 'machine_name',
-      '#title' => t('Machine name'),
       '#default_value' => $this->entity->id(),
       '#disabled' => !$this->entity->isNew(),
       '#maxlength' => 64,
diff --git a/core/modules/block/lib/Drupal/block/BlockFormController.php b/core/modules/block/lib/Drupal/block/BlockFormController.php
index f562a68..8e25268 100644
--- a/core/modules/block/lib/Drupal/block/BlockFormController.php
+++ b/core/modules/block/lib/Drupal/block/BlockFormController.php
@@ -29,7 +29,6 @@ public function form(array $form, array &$form_state) {
 
     $form['machine_name'] = array(
       '#type' => 'machine_name',
-      '#title' => t('Machine name'),
       '#maxlength' => 64,
       '#description' => t('A unique name to save this block configuration. Must be alpha-numeric and be underscore separated.'),
       '#default_value' => $entity->id(),
diff --git a/core/modules/content_translation/content_translation.admin.inc b/core/modules/content_translation/content_translation.admin.inc
index 63e71fc..bf835ca 100644
--- a/core/modules/content_translation/content_translation.admin.inc
+++ b/core/modules/content_translation/content_translation.admin.inc
@@ -89,6 +89,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$
         if ($fields) {
           $form['settings'][$entity_type][$bundle]['translatable'] = array(
             '#type' => 'checkbox',
+            '#title' => t($bundle),
             '#default_value' => content_translation_enabled($entity_type, $bundle),
           );
 
@@ -99,6 +100,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$
             $form['settings'][$entity_type][$bundle]['fields'][$field_name] = array(
               '#label' => $instance['label'],
               '#type' => 'checkbox',
+              '#title' => $instance['label'],
               '#default_value' => $field['translatable'],
             );
             $column_element = content_translation_field_sync_widget($field, $instance);
diff --git a/core/modules/entity/lib/Drupal/entity/Form/EntityDisplayModeFormBase.php b/core/modules/entity/lib/Drupal/entity/Form/EntityDisplayModeFormBase.php
index 787432a..615448f 100644
--- a/core/modules/entity/lib/Drupal/entity/Form/EntityDisplayModeFormBase.php
+++ b/core/modules/entity/lib/Drupal/entity/Form/EntityDisplayModeFormBase.php
@@ -73,7 +73,6 @@ public function form(array $form, array &$form_state) {
 
     $form['id'] = array(
       '#type' => 'machine_name',
-      '#title' => t('Machine-readable name'),
       '#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
       '#disabled' => !$this->entity->isNew(),
       '#default_value' => $this->entity->id(),
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
index 654cbbe..39f0c34 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
@@ -180,10 +180,19 @@ protected function formMultipleElements(EntityInterface $entity, array $items, $
     for ($delta = 0; $delta <= $max; $delta++) {
       // For multiple fields, title and description are handled by the wrapping
       // table.
-      $element = array(
-        '#title' => $is_multiple ? '' : $title,
-        '#description' => $is_multiple ? '' : $description,
-      );
+      if ($is_multiple) {
+        $element = array(
+          '#title' => '',
+          '#description' => '',
+          '#property_validate' => array(),
+        );
+      }
+      else {
+        $element = array(
+          '#title' => $title,
+          '#description' => $description,
+        );
+      }
       $element = $this->formSingleElement($entity, $items, $delta, $langcode, $element, $form, $form_state);
 
       if ($element) {
diff --git a/core/modules/filter/lib/Drupal/filter/FilterFormatFormControllerBase.php b/core/modules/filter/lib/Drupal/filter/FilterFormatFormControllerBase.php
index 98495d5..335abf1 100644
--- a/core/modules/filter/lib/Drupal/filter/FilterFormatFormControllerBase.php
+++ b/core/modules/filter/lib/Drupal/filter/FilterFormatFormControllerBase.php
@@ -79,6 +79,7 @@ public function form(array $form, array &$form_state) {
     );
     $form['format'] = array(
       '#type' => 'machine_name',
+      '#title' => t('Machine name'),
       '#required' => TRUE,
       '#default_value' => $format->id(),
       '#maxlength' => 255,
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Condition/NodeType.php b/core/modules/node/lib/Drupal/node/Plugin/Condition/NodeType.php
index 4f30bb7..8622a93 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/Condition/NodeType.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/Condition/NodeType.php
@@ -39,6 +39,7 @@ public function buildForm(array $form, array &$form_state) {
       $options[$type->type] = $type->name;
     }
     $form['bundles'] = array(
+      '#title' => t('Node types'),
       '#type' => 'checkboxes',
       '#options' => $options,
       '#required' => TRUE,
diff --git a/core/modules/system/lib/Drupal/system/Form/DateFormatFormBase.php b/core/modules/system/lib/Drupal/system/Form/DateFormatFormBase.php
index 4d347c5..5c22f7c 100644
--- a/core/modules/system/lib/Drupal/system/Form/DateFormatFormBase.php
+++ b/core/modules/system/lib/Drupal/system/Form/DateFormatFormBase.php
@@ -132,7 +132,6 @@ public function form(array $form, array &$form_state) {
 
     $form['id'] = array(
       '#type' => 'machine_name',
-      '#title' => t('Machine-readable name'),
       '#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
       '#disabled' => !$this->entity->isNew(),
       '#default_value' => $this->entity->id(),
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index ac42ea3..0fa81d7 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -329,6 +329,9 @@ function system_element_info() {
     '#autocomplete_path' => FALSE,
     '#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'),
     '#pre_render' => array('form_pre_render_textfield'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__textfield',
     '#theme_wrappers' => array('form_element'),
   );
@@ -339,6 +342,9 @@ function system_element_info() {
     '#autocomplete_path' => FALSE,
     '#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'),
     '#pre_render' => array('form_pre_render_tel'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__tel',
     '#theme_wrappers' => array('form_element'),
   );
@@ -351,6 +357,9 @@ function system_element_info() {
     '#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'),
     '#element_validate' => array('form_validate_email'),
     '#pre_render' => array('form_pre_render_email'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__email',
     '#theme_wrappers' => array('form_element'),
   );
@@ -362,6 +371,9 @@ function system_element_info() {
     '#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'),
     '#element_validate' => array('form_validate_url'),
     '#pre_render' => array('form_pre_render_url'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__url',
     '#theme_wrappers' => array('form_element'),
   );
@@ -372,6 +384,9 @@ function system_element_info() {
     '#autocomplete_path' => FALSE,
     '#process' => array('form_process_autocomplete', 'ajax_process_form'),
     '#pre_render' => array('form_pre_render_search'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__search',
     '#theme_wrappers' => array('form_element'),
   );
@@ -381,6 +396,9 @@ function system_element_info() {
     '#process' => array('ajax_process_form'),
     '#element_validate' => array('form_validate_number'),
     '#pre_render' => array('form_pre_render_number'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__number',
     '#theme_wrappers' => array('form_element'),
   );
@@ -392,6 +410,9 @@ function system_element_info() {
     '#process' => array('ajax_process_form'),
     '#element_validate' => array('form_validate_number'),
     '#pre_render' => array('form_pre_render_range'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__range',
     '#theme_wrappers' => array('form_element'),
   );
@@ -400,6 +421,9 @@ function system_element_info() {
     '#process' => array('ajax_process_form'),
     '#element_validate' => array('form_validate_color'),
     '#pre_render' => array('form_pre_render_color'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__color',
     '#theme_wrappers' => array('form_element'),
   );
@@ -413,6 +437,9 @@ function system_element_info() {
     '#process' => array('form_process_machine_name', 'form_process_autocomplete', 'ajax_process_form'),
     '#element_validate' => array('form_validate_machine_name'),
     '#pre_render' => array('form_pre_render_textfield'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__textfield',
     '#theme_wrappers' => array('form_element'),
   );
@@ -422,6 +449,9 @@ function system_element_info() {
     '#maxlength' => 128,
     '#process' => array('ajax_process_form', 'form_process_pattern'),
     '#pre_render' => array('form_pre_render_password'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__password',
     '#theme_wrappers' => array('form_element'),
   );
@@ -436,12 +466,18 @@ function system_element_info() {
     '#rows' => 5,
     '#resizable' => 'vertical',
     '#process' => array('ajax_process_form'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'textarea',
     '#theme_wrappers' => array('form_element'),
   );
   $types['radios'] = array(
     '#input' => TRUE,
     '#process' => array('form_process_radios'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme_wrappers' => array('radios'),
     '#pre_render' => array('form_pre_render_conditional_form_element'),
   );
@@ -450,6 +486,9 @@ function system_element_info() {
     '#default_value' => NULL,
     '#process' => array('ajax_process_form'),
     '#pre_render' => array('form_pre_render_radio'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__radio',
     '#theme_wrappers' => array('form_element'),
     '#title_display' => 'after',
@@ -458,6 +497,9 @@ function system_element_info() {
     '#input' => TRUE,
     '#process' => array('form_process_checkboxes'),
     '#pre_render' => array('form_pre_render_conditional_form_element'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme_wrappers' => array('checkboxes'),
   );
   $types['checkbox'] = array(
@@ -465,6 +507,9 @@ function system_element_info() {
     '#return_value' => 1,
     '#process' => array('form_process_checkbox', 'ajax_process_form'),
     '#pre_render' => array('form_pre_render_checkbox'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__checkbox',
     '#theme_wrappers' => array('form_element'),
     '#title_display' => 'after',
@@ -473,6 +518,9 @@ function system_element_info() {
     '#input' => TRUE,
     '#multiple' => FALSE,
     '#process' => array('form_process_select', 'ajax_process_form'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'select',
     '#theme_wrappers' => array('form_element'),
     '#options' => array(),
@@ -480,15 +528,24 @@ function system_element_info() {
   $types['language_select'] = array(
     '#input' => TRUE,
     '#default_value' => Language::LANGCODE_NOT_SPECIFIED,
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
   );
   $types['weight'] = array(
     '#input' => TRUE,
     '#delta' => 10,
     '#default_value' => 0,
     '#process' => array('form_process_weight', 'ajax_process_form'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
   );
   $types['date'] = array(
     '#input' => TRUE,
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'date',
     '#theme_wrappers' => array('form_element'),
   );
@@ -498,6 +555,9 @@ function system_element_info() {
     '#process' => array('form_process_file'),
     '#size' => 60,
     '#pre_render' => array('form_pre_render_file'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme' => 'input__file',
     '#theme_wrappers' => array('form_element'),
   );
@@ -543,6 +603,9 @@ function system_element_info() {
     '#value' => NULL,
     '#process' => array('form_process_group', 'ajax_process_form'),
     '#pre_render' => array('form_pre_render_group'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme_wrappers' => array('fieldset'),
   );
   $types['details'] = array(
@@ -550,6 +613,9 @@ function system_element_info() {
     '#value' => NULL,
     '#process' => array('form_process_group', 'ajax_process_form'),
     '#pre_render' => array('form_pre_render_details', 'form_pre_render_group'),
+    '#property_validate' => array(
+      '#title' => array('form_element_validate_title'),
+    ),
     '#theme_wrappers' => array('details'),
   );
   $types['vertical_tabs'] = array(
diff --git a/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module b/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
index 1682c01..80653da 100644
--- a/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
+++ b/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
@@ -49,6 +49,7 @@ function ajax_forms_test_simple_form($form, &$form_state) {
 
   $form = array();
   $form['select'] = array(
+    '#title' => t('Color'),
     '#type' => 'select',
     '#options' => array(
       'red' => 'red',
diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc
index bb486ff..1fafdb0 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -4,6 +4,7 @@
  * @file
  * Admin page callback file for the user module.
  */
+use Drupal\Component\Utility\String;
 
 /**
  * Page callback: User administration page.
@@ -143,7 +144,7 @@ function user_admin_permissions($form, $form_state, $rid = NULL) {
           'restrict access' => FALSE,
           'warning' => !empty($perm_item['restrict access']) ? t('Warning: Give to trusted roles only; this permission has security implications.') : '',
         );
-        $options[$perm] = '';
+        $options[$perm] = $perm_item['title'];
         $user_permission_description = array(
           '#theme' => 'user_permission_description',
           '#permission_item' => $perm_item,
@@ -167,6 +168,7 @@ function user_admin_permissions($form, $form_state, $rid = NULL) {
   // Have to build checkboxes here after checkbox arrays are built
   foreach ($role_names as $rid => $name) {
     $form['checkboxes'][$rid] = array(
+      '#title' => String::checkPlain($name),
       '#type' => 'checkboxes',
       '#options' => $options,
       '#default_value' => isset($status[$rid]) ? $status[$rid] : array(),
@@ -229,6 +231,7 @@ function theme_user_admin_permissions($variables) {
         $form['checkboxes'][$rid][$key]['#title_display'] = 'invisible';
         $row[] = array('data' => drupal_render($form['checkboxes'][$rid][$key]), 'class' => array('checkbox'));
       }
+      hide($form['checkboxes']);
     }
     $rows[] = $row;
   }
diff --git a/core/modules/views/css/views.exposed_form.css b/core/modules/views/css/views.exposed_form.css
new file mode 100644
index 0000000..273e598
--- /dev/null
+++ b/core/modules/views/css/views.exposed_form.css
@@ -0,0 +1,20 @@
+/**
+ * @file
+ * Styling for Views exposed forms.
+ */
+.views-exposed-form .form-item {
+  /* Display exposed form elements horizontally. */
+  float: left; /* LTR */
+  margin-right: .25em; /* LTR */
+}
+[dir="rtl"] .views-exposed-form .form-item {
+  float: right;
+  margin-left: .25em;
+}
+
+.views-exposed-form .form-actions {
+  clear: left; /* LTR */
+}
+[dir="rtl"] .views-exposed-form .form-actions {
+  clear: right;
+}
diff --git a/core/modules/views/css/views.module.css b/core/modules/views/css/views.module.css
index 7ca2f49..a29083c 100644
--- a/core/modules/views/css/views.module.css
+++ b/core/modules/views/css/views.module.css
@@ -1,13 +1,3 @@
-.views-exposed-form .views-exposed-widget {
-  display: inline-block;
-}
-
-.views-exposed-form .form-item,
-.views-exposed-form .form-submit {
-  margin-top: 0;
-  margin-bottom: 0;
-}
-
 /* table style column align */
 .views-align-left {
   text-align: left;
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
index 57691f1..79795d2 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
@@ -305,6 +305,7 @@ public function buildOptionsForm(&$form, &$form_state) {
         $form['#title'] .= t('The menu path or URL of this view');
         $form['path'] = array(
           '#type' => 'textfield',
+          '#title' => t('Path'),
           '#description' => t('This view will be displayed by visiting this path on your site. You may use "%" in your URL to represent values that will be used for contextual filters: For example, "node/%/feed".'),
           '#default_value' => $this->getOption('path'),
           '#field_prefix' => '<span dir="ltr">' . url(NULL, array('absolute' => TRUE)),
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
index 60ba107..aa40b27 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\filter;
 
 use Drupal\views\Plugin\views\HandlerBase;
+use Drupal\Component\Utility\String;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\Component\Annotation\Plugin;
 use Drupal\views\ViewExecutable;
@@ -748,6 +749,7 @@ public function groupForm(&$form, &$form_state) {
       $value = $this->options['group_info']['identifier'];
 
       $form[$value] = array(
+        '#title' => String::checkPlain($this->options['group_info']['label']),
         '#type' => $this->options['group_info']['widget'],
         '#default_value' => $this->group_info,
         '#options' => $groups,
@@ -788,10 +790,6 @@ public function buildExposedForm(&$form, &$form_state) {
       $this->operatorForm($form, $form_state);
       $form[$operator] = $form['operator'];
 
-      if (isset($form[$operator]['#title'])) {
-        unset($form[$operator]['#title']);
-      }
-
       $this->exposedTranslate($form[$operator], 'operator');
 
       unset($form['operator']);
@@ -801,11 +799,11 @@ public function buildExposedForm(&$form, &$form_state) {
     if (!empty($this->options['expose']['identifier'])) {
       $value = $this->options['expose']['identifier'];
       $this->valueForm($form, $form_state);
-      $form[$value] = $form['value'];
-
-      if (isset($form[$value]['#title']) && !empty($form[$value]['#type']) && $form[$value]['#type'] != 'checkbox') {
-        unset($form[$value]['#title']);
+      // If no title was specified, prevent validation errors.
+      if (!isset($form['value']['#title']) || trim($form['value']['#title']) == '') {
+        $form['value']['#property_validate']['#title'] = array();
       }
+      $form[$value] = $form['value'];
 
       $this->exposedTranslate($form[$value], 'value');
 
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
index a84eb92..62fa461 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
@@ -209,8 +209,10 @@ public function buildForm(array $form, array &$form_state) {
     $this->buildFilters($form, $form_state);
     $this->buildSorts($form, $form_state);
 
+    // @Todo: Consider removing this fieldset or converting it to #type details
     $form['displays']['page'] = array(
       '#type' => 'fieldset',
+      '#title' => t('Page settings'),
       '#attributes' => array('class' => array('views-attachment', 'fieldset-no-legend')),
       '#tree' => TRUE,
     );
@@ -246,8 +248,10 @@ public function buildForm(array $form, array &$form_state) {
       '#type' => 'textfield',
       '#field_prefix' => $path_prefix,
     );
+    // @Todo: Consider removing this fieldset or converting it to #type details
     $form['displays']['page']['options']['style'] = array(
       '#type' => 'fieldset',
+      '#title' => t('Page display settings'),
       '#attributes' => array('class' => array('container-inline', 'fieldset-no-legend')),
     );
 
@@ -352,8 +356,10 @@ public function buildForm(array $form, array &$form_state) {
       return $form;
     }
 
+    // @Todo: Consider removing this fieldset or converting it to #type details
     $form['displays']['block'] = array(
       '#type' => 'fieldset',
+      '#title' => t('Block settings'),
       '#attributes' => array('class' => array('views-attachment', 'fieldset-no-legend')),
       '#tree' => TRUE,
     );
@@ -383,8 +389,10 @@ public function buildForm(array $form, array &$form_state) {
       '#title' => t('Block title'),
       '#type' => 'textfield',
     );
+    // @Todo: Consider removing this fieldset or converting it to #type details
     $form['displays']['block']['options']['style'] = array(
       '#type' => 'fieldset',
+      '#title' => t('Block display settings'),
       '#attributes' => array('class' => array('container-inline', 'fieldset-no-legend')),
     );
 
diff --git a/core/modules/views/templates/views-exposed-form.html.twig b/core/modules/views/templates/views-exposed-form.html.twig
index d4986e6..5a34f2f 100644
--- a/core/modules/views/templates/views-exposed-form.html.twig
+++ b/core/modules/views/templates/views-exposed-form.html.twig
@@ -4,21 +4,7 @@
  * Default theme implementation of a views exposed form.
  *
  * Available variables:
- * - widgets: A list of exposed form widgets. Each widget contains:
- *   - label: The sanitized label of the widget.
- *   - id: The ID of the widget, if available.
- *   - operator: The select element for the operator widget.
- *   - description: The sanitized description of the widget.
- *   - widget: The widget itself.
- *   - index: the widget's row index.
  * - form: A render element representing the form.
- *   - sort_by: An optional select element to sort the view by fields.
- *   - sort_order: An optional select element with ascending or
- *     descending order options.
- *   - items_per_page: An optional select element for the available items per
- *     page.
- *   - offset: An optional textfield to define the offset of the view.
- *   - reset_button: An optional button to reset the exposed filter applied.
  *
  * @see template_preprocess_views_exposed_form()
  *
@@ -32,55 +18,6 @@
   #}
 {{ q }}
 {% endif %}
-<div class="views-exposed-form">
-  <div class="views-exposed-widgets clearfix">
-    {% for index, widget in widgets %}
-      <div id="{{ widget.id }}-wrapper" class="views-exposed-widget views-widget-{{ index }}">
-          {% if widget.label %}
-          <label for="{{ widget.id }}">
-            {{ widget.label }}
-          </label>
-        {% endif %}
-        {% if widget.operator %}
-          <div class="views-operator">
-            {{ widget.operator }}
-          </div>
-        {% endif %}
-        <div class="views-widget">
-          {{ widget.widget }}
-        </div>
-        {% if widget.description %}
-          <div class="description">
-            {{ widget.description }}
-          </div>
-        {% endif %}
-      </div>
-    {% endfor %}
-    {% if form.sort_by %}
-      <div class="views-exposed-widget views-widget-sort-by">
-        {{ form.sort_by }}
-      </div>
-      <div class="views-exposed-widget views-widget-sort-order">
-        {{ form.sort_order }}
-      </div>
-    {% endif %}
-    {% if form.items_per_page %}
-      <div class="views-exposed-widget views-widget-per-page">
-        {{ form.items_per_page }}
-      </div>
-    {% endif %}
-    {% if form.offset %}
-      <div class="views-exposed-widget views-widget-offset">
-        {{ form.offset }}
-      </div>
-    {% endif %}
-    <div class="views-exposed-widget views-submit-button">
-      {{ form }}
-    </div>
-    {% if form.reset_button %}
-      <div class="views-exposed-widget views-reset-button">
-        {{ form.reset_button }}
-      </div>
-    {% endif %}
-  </div>
+<div class="views-exposed-form clearfix">
+  {{ form }}
 </div>
diff --git a/core/modules/views/tests/modules/views_test_data/views_test_data.views_execution.inc b/core/modules/views/tests/modules/views_test_data/views_test_data.views_execution.inc
index e5a4277..701624b 100644
--- a/core/modules/views/tests/modules/views_test_data/views_test_data.views_execution.inc
+++ b/core/modules/views/tests/modules/views_test_data/views_test_data.views_execution.inc
@@ -18,7 +18,7 @@ function views_test_data_views_query_substitutions(ViewExecutable $view) {
 /**
  * Implements hook_views_form_substitutions().
  */
-function views_test_data_views_form_substitutions(ViewExecutable $view) {
+function views_test_data_views_form_substitutions() {
   Drupal::state()->set('views_hook_test_views_form_substitutions', TRUE);
 }
 
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 2b0a75a..d17e3e2 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -830,6 +830,13 @@ function views_library_info() {
       array('system', 'drupal'),
     ),
   );
+  $libraries['views.exposed-form'] = array(
+    'title' => 'Views exposed form',
+    'version' => VERSION,
+    'css' => array(
+      "$path/css/views.exposed_form.css",
+    ),
+  );
 
   return $libraries;
 }
@@ -1351,7 +1358,8 @@ function views_exposed_form($form, &$form_state) {
     }
   }
 
-  $form['submit'] = array(
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array(
     // Prevent from showing up in $_GET.
     '#name' => '',
     '#type' => 'submit',
diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc
index 3d1a84d..ef398dc 100644
--- a/core/modules/views/views.theme.inc
+++ b/core/modules/views/views.theme.inc
@@ -1035,52 +1035,17 @@ function template_preprocess_views_view_row_rss(&$variables) {
 function template_preprocess_views_exposed_form(&$variables) {
   $form = &$variables['form'];
 
-  // Put all single checkboxes together in the last spot.
-  $checkboxes = array();
-
   if (!empty($form['q'])) {
     $variables['q'] = $form['q'];
   }
 
-  $variables['widgets'] = array();
-  foreach ($form['#info'] as $id => $info) {
-    // Set aside checkboxes.
-    if (isset($form[$info['value']]['#type']) && $form[$info['value']]['#type'] == 'checkbox') {
-      $checkboxes[] = $form[$info['value']];
-      continue;
-    }
-    $widget = new stdClass();
-    // set up defaults so that there's always something there.
-    $widget->label = $widget->operator = $widget->widget = $widget->description = '';
-
-    $widget->id = isset($form[$info['value']]['#id']) ? $form[$info['value']]['#id'] : '';
+  // Include basic theming for exposed forms.
+  $form['#attached']['library'][] = array('views', 'views.exposed-form');
 
+  foreach ($form['#info'] as $id => $info) {
     if (!empty($info['label'])) {
-      $widget->label = check_plain($info['label']);
-    }
-    if (!empty($info['operator']) && isset($form[$info['operator']])) {
-      $widget->operator = $form[$info['operator']];
+      $form[$info['value']]['#title'] = $info['label'];
     }
-
-    $widget->widget = $form[$info['value']];
-
-    if (!empty($info['description'])) {
-      $widget->description = check_plain($info['description']);
-    }
-
-    $variables['widgets'][$id] = $widget;
-    // Unset the widget, so that it doesn't get rendered twice.
-    unset($form[$info['value']]);
-  }
-
-  // Wrap up all the checkboxes we set aside into a widget.
-  if (!empty($checkboxes)) {
-    $widget = new stdClass();
-    // set up defaults so that there's always something there.
-    $widget->label = $widget->operator = $widget->widget = NULL;
-    $widget->id = 'checkboxes';
-    $widget->widget = $checkboxes;
-    $variables['widgets']['checkboxes'] = $widget;
   }
 }
 
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/Rearrange.php b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/Rearrange.php
index c8d8a94..c43d17c 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/Rearrange.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/Rearrange.php
@@ -101,6 +101,7 @@ public function buildForm(array $form, array &$form_state) {
         );
       }
       else {
+        $name = $id;
         $form['fields'][$id]['name'] = array('#markup' => t('Broken field @id', array('@id' => $id)));
       }
 
@@ -108,10 +109,14 @@ public function buildForm(array $form, array &$form_state) {
         '#type' => 'textfield',
         '#default_value' => ++$count,
         '#attributes' => array('class' => array('weight')),
+        '#title_display' => 'invisible',
+        '#title' => t('Weight for @title', array('@title' => $name)),
       );
 
       $form['fields'][$id]['removed'] = array(
         '#type' => 'checkbox',
+        '#title' => t('Remove @title', array('@title' => $name)),
+        '#title_display' => 'invisible',
         '#id' => 'views-removed-' . $id,
         '#attributes' => array('class' => array('views-remove-checkbox')),
         '#default_value' => 0,
@@ -119,11 +124,6 @@ public function buildForm(array $form, array &$form_state) {
       );
     }
 
-    $name = NULL;
-    if (isset($form_state['update_name'])) {
-      $name = $form_state['update_name'];
-    }
-
     $view->getStandardButtons($form, $form_state, 'views_ui_rearrange_form');
 
     return $form;
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Form/BasicSettingsForm.php b/core/modules/views_ui/lib/Drupal/views_ui/Form/BasicSettingsForm.php
index bfac4e6..1397e00 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Form/BasicSettingsForm.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/BasicSettingsForm.php
@@ -95,6 +95,7 @@ public function buildForm(array $form, array &$form_state) {
 
     $form['live_preview']['options']['ui_show_sql_query_where'] = array(
       '#type' => 'radios',
+      '#title' => t('Show SQL query'),
       '#options' => array(
         'above' => t('Above the preview'),
         'below' => t('Below the preview'),
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php
index 4ad9376..97c7ef6 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php
@@ -74,8 +74,10 @@ public function form(array $form, array &$form_state) {
     $form['#attached']['js'][] = drupal_get_path('module', 'views_ui') . '/js/views-admin.js';
     $form['#attributes']['class'] = array('views-admin');
 
+      // @Todo: Consider removing this fieldset.
     $form['name'] = array(
       '#type' => 'fieldset',
+      '#title' => t('Biew basic information'),
       '#attributes' => array('class' => array('fieldset-no-legend')),
     );
 
@@ -123,8 +125,10 @@ public function form(array $form, array &$form_state) {
 
     // Create the part of the form that allows the user to select the basic
     // properties of what the view will display.
+    // @todo: Consider removing the fieldset below.
     $form['displays']['show'] = array(
       '#type' => 'fieldset',
+      '#title' => t('View settings'),
       '#tree' => TRUE,
       '#attributes' => array('class' => array('container-inline')),
     );
